Merge "Add internal power mode changed broadcast"
diff --git a/Android.mk b/Android.mk
index 137ef85..c1c74ea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -261,7 +261,7 @@
core/java/android/view/IApplicationToken.aidl \
core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
core/java/android/view/IAssetAtlas.aidl \
- core/java/android/view/IDockDividerVisibilityListener.aidl \
+ core/java/android/view/IDockedStackListener.aidl \
core/java/android/view/IGraphicsStats.aidl \
core/java/android/view/IInputFilter.aidl \
core/java/android/view/IInputFilterHost.aidl \
@@ -308,7 +308,7 @@
core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
core/java/com/android/internal/textservice/ITextServicesManager.aidl \
core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
- core/java/com/android/internal/view/IDropPermissionHolder.aidl \
+ core/java/com/android/internal/view/IDropPermissions.aidl \
core/java/com/android/internal/view/IInputContext.aidl \
core/java/com/android/internal/view/IInputContextCallback.aidl \
core/java/com/android/internal/view/IInputMethod.aidl \
@@ -498,6 +498,7 @@
frameworks/base/graphics/java/android/graphics/PointF.aidl \
frameworks/base/graphics/java/android/graphics/RectF.aidl \
frameworks/base/graphics/java/android/graphics/Rect.aidl \
+ frameworks/base/graphics/java/android/graphics/drawable/Icon.aidl \
frameworks/base/core/java/android/accounts/AuthenticatorDescription.aidl \
frameworks/base/core/java/android/accounts/Account.aidl \
frameworks/base/core/java/android/app/admin/SystemUpdatePolicy.aidl \
diff --git a/api/current.txt b/api/current.txt
index df6c473a3..2417493 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67,7 +67,6 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -2114,22 +2113,6 @@
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_Material = 16974372; // 0x1030224
- field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
- field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
- field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
- field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
- field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
- field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
- field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
- field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
- field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
- field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
- field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
- field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
- field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
- field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2143,7 +2126,7 @@
field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
- field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+ field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -3374,6 +3357,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3519,6 +3503,7 @@
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -3553,6 +3538,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
+ method public void setVrMode(boolean);
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -4095,11 +4081,14 @@
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4239,7 +4228,7 @@
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4851,6 +4840,7 @@
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5017,6 +5007,7 @@
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5206,6 +5197,7 @@
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5658,8 +5650,10 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
@@ -5753,6 +5747,7 @@
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+ method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5763,8 +5758,11 @@
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
+ method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
+ method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5782,6 +5780,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5795,6 +5794,7 @@
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+ method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5802,6 +5802,7 @@
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
+ method public void reboot(android.content.ComponentName);
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
@@ -5810,6 +5811,7 @@
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
+ method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
@@ -5820,9 +5822,11 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
+ method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -5843,6 +5847,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7568,11 +7573,12 @@
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7586,7 +7592,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -8488,6 +8494,7 @@
field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
+ field public static final int FLAG_ACTIVITY_LAUNCH_TO_SIDE = 4096; // 0x1000
field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
@@ -8999,6 +9006,7 @@
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+ field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9094,6 +9102,7 @@
field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+ field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
@@ -9438,8 +9447,10 @@
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+ method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.lang.String[] getPackagesForUid(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -9510,6 +9521,7 @@
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9531,6 +9543,7 @@
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
+ field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
@@ -9560,15 +9573,15 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
- field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9580,10 +9593,17 @@
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+ field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -9966,6 +9986,7 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
+ method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -10597,6 +10618,7 @@
method public void setVersion(int);
method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+ method public void validateSql(java.lang.String, android.os.CancellationSignal);
method public deprecated boolean yieldIfContended();
method public boolean yieldIfContendedSafely();
method public boolean yieldIfContendedSafely(long);
@@ -10831,7 +10853,7 @@
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10841,6 +10863,7 @@
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -10854,7 +10877,7 @@
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11258,14 +11281,14 @@
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -18234,7 +18257,6 @@
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18258,8 +18280,6 @@
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -18272,8 +18292,6 @@
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -18369,8 +18387,6 @@
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -22439,6 +22455,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
+ method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -26851,6 +26868,279 @@
method public abstract void onMessage(int, int, int, int, java.lang.String);
}
+ public class GLES32 extends android.opengl.GLES31 {
+ method public static void glBlendBarrier();
+ method public static void glBlendEquationSeparatei(int, int, int);
+ method public static void glBlendEquationi(int, int);
+ method public static void glBlendFuncSeparatei(int, int, int, int, int);
+ method public static void glBlendFunci(int, int, int);
+ method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+ method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+ method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+ method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+ method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+ method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+ method public static void glDisablei(int, int);
+ method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+ method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+ method public static void glEnablei(int, int);
+ method public static void glFramebufferTexture(int, int, int, int);
+ method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+ method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+ method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+ method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+ method public static int glGetGraphicsResetStatus();
+ method public static java.lang.String glGetObjectLabel(int, int);
+ method public static java.lang.String glGetObjectPtrLabel(long);
+ method public static long glGetPointerv(int);
+ method public static void glGetSamplerParameterIiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIiv(int, int, int[], int);
+ method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIuiv(int, int, int[], int);
+ method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformfv(int, int, int, float[], int);
+ method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+ method public static void glGetnUniformiv(int, int, int, int[], int);
+ method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformuiv(int, int, int, int[], int);
+ method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+ method public static boolean glIsEnabledi(int, int);
+ method public static void glMinSampleShading(float);
+ method public static void glObjectLabel(int, int, int, java.lang.String);
+ method public static void glObjectPtrLabel(long, java.lang.String);
+ method public static void glPatchParameteri(int, int);
+ method public static void glPopDebugGroup();
+ method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+ method public static void glPushDebugGroup(int, int, int, java.lang.String);
+ method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+ method public static void glSamplerParameterIiv(int, int, int[], int);
+ method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glSamplerParameterIuiv(int, int, int[], int);
+ method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexBuffer(int, int, int);
+ method public static void glTexBufferRange(int, int, int, int, int);
+ method public static void glTexParameterIiv(int, int, int[], int);
+ method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glTexParameterIuiv(int, int, int[], int);
+ method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+ field public static final int GL_BUFFER = 33504; // 0x82e0
+ field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+ field public static final int GL_COLORBURN = 37530; // 0x929a
+ field public static final int GL_COLORDODGE = 37529; // 0x9299
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+ field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+ field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+ field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+ field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+ field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+ field public static final int GL_DARKEN = 37527; // 0x9297
+ field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+ field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+ field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+ field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+ field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+ field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+ field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+ field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+ field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+ field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+ field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+ field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+ field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+ field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+ field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+ field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+ field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+ field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+ field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+ field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+ field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+ field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+ field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+ field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+ field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+ field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+ field public static final int GL_DIFFERENCE = 37534; // 0x929e
+ field public static final int GL_EXCLUSION = 37536; // 0x92a0
+ field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+ field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+ field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+ field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+ field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+ field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+ field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+ field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+ field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+ field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+ field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+ field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+ field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+ field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+ field public static final int GL_HARDLIGHT = 37531; // 0x929b
+ field public static final int GL_HSL_COLOR = 37551; // 0x92af
+ field public static final int GL_HSL_HUE = 37549; // 0x92ad
+ field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+ field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+ field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+ field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+ field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+ field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+ field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+ field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+ field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+ field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+ field public static final int GL_ISOLINES = 36474; // 0x8e7a
+ field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+ field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+ field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+ field public static final int GL_LIGHTEN = 37528; // 0x9298
+ field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+ field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+ field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+ field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+ field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+ field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+ field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+ field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+ field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+ field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+ field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+ field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+ field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+ field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+ field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+ field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+ field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+ field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+ field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+ field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+ field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+ field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+ field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+ field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+ field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+ field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+ field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+ field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+ field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+ field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+ field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+ field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+ field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+ field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+ field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+ field public static final int GL_MULTIPLY = 37524; // 0x9294
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+ field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+ field public static final int GL_OVERLAY = 37526; // 0x9296
+ field public static final int GL_PATCHES = 14; // 0xe
+ field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+ field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+ field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+ field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+ field public static final int GL_PROGRAM = 33506; // 0x82e2
+ field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+ field public static final int GL_QUADS = 7; // 0x7
+ field public static final int GL_QUERY = 33507; // 0x82e3
+ field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+ field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+ field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+ field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+ field public static final int GL_SAMPLER = 33510; // 0x82e6
+ field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+ field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+ field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+ field public static final int GL_SCREEN = 37525; // 0x9295
+ field public static final int GL_SHADER = 33505; // 0x82e1
+ field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+ field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+ field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+ field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+ field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+ field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+ field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+ field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+ field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+ field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+ field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+ field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+ field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+ field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+ field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+ field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+ field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+ field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+ field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+ field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+ field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+ field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+ field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+ field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+ field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+ field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+ field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+ field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+ field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+ field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+ }
+
+ public static abstract interface GLES32.DebugProc {
+ method public abstract void onMessage(int, int, int, int, java.lang.String);
+ }
+
public class GLException extends java.lang.RuntimeException {
ctor public GLException(int);
ctor public GLException(int, java.lang.String);
@@ -28870,6 +29160,9 @@
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -28890,6 +29183,10 @@
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -28945,6 +29242,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -29313,6 +29611,7 @@
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
field public static final java.lang.String IS_READ = "is_read";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
field public static final int MISSED_TYPE = 3; // 0x3
field public static final java.lang.String NEW = "new";
@@ -30483,7 +30782,7 @@
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
- field public static final int FLAG_ARCHIVE = 2048; // 0x800
+ field public static final int FLAG_ARCHIVE = 1024; // 0x400
field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
@@ -30492,9 +30791,8 @@
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
- field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
- field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
}
@@ -30921,6 +31219,7 @@
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -30937,6 +31236,7 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
+ field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -31582,6 +31882,7 @@
public static final class VoicemailContract.Status implements android.provider.BaseColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -31598,6 +31899,9 @@
field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+ field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+ field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+ field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -31614,6 +31918,7 @@
field public static final java.lang.String HAS_CONTENT = "has_content";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -32805,6 +33110,7 @@
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -33220,6 +33526,7 @@
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
public class NotificationAssistantService.Adjustment {
@@ -33249,6 +33556,7 @@
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
method public final void setNotificationsShown(java.lang.String[]);
+ field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -33258,6 +33566,7 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
}
public static class NotificationListenerService.Ranking {
@@ -33329,10 +33638,13 @@
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -34593,6 +34905,7 @@
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
@@ -36431,7 +36744,6 @@
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -36443,8 +36755,10 @@
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInstaller getPackageInstaller();
+ method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.String[] getPackagesForUid(int);
method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -36483,7 +36797,6 @@
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void verifyPendingInstall(int, int);
@@ -38873,7 +39186,7 @@
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39304,7 +39617,6 @@
method public int getAction();
method public android.content.ClipData getClipData();
method public android.content.ClipDescription getClipDescription();
- method public android.view.DropPermissionHolder getDropPermissionHolder();
method public java.lang.Object getLocalState();
method public boolean getResult();
method public float getX();
@@ -39319,12 +39631,8 @@
field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
}
- public class DropPermissionHolder implements android.os.Parcelable {
- method public int describeContents();
- method public void grant();
- method public void revoke();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+ public final class DropPermissions {
+ method public void release();
}
public class FocusFinder {
@@ -40250,6 +40558,8 @@
field public static final int AXIS_LTRIGGER = 17; // 0x11
field public static final int AXIS_ORIENTATION = 8; // 0x8
field public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
field public static final int AXIS_RTRIGGER = 18; // 0x12
field public static final int AXIS_RUDDER = 20; // 0x14
field public static final int AXIS_RX = 12; // 0xc
@@ -40785,6 +41095,7 @@
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -40911,6 +41222,7 @@
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -41011,6 +41323,7 @@
method public void setPaddingRelative(int, int, int, int);
method public void setPivotX(float);
method public void setPivotY(float);
+ method public void setPointerCapture();
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
method public final void setRight(int);
@@ -59422,8 +59735,8 @@
method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
method public int end();
method public int end(int);
- method public boolean find(int);
method public boolean find();
+ method public boolean find(int);
method public java.lang.String group();
method public java.lang.String group(int);
method public int groupCount();
@@ -59451,8 +59764,8 @@
}
public final class Pattern implements java.io.Serializable {
- method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public static java.util.regex.Pattern compile(java.lang.String);
+ method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public int flags();
method public java.util.regex.Matcher matcher(java.lang.CharSequence);
method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -59467,6 +59780,7 @@
field public static final int LITERAL = 16; // 0x10
field public static final int MULTILINE = 8; // 0x8
field public static final int UNICODE_CASE = 64; // 0x40
+ field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
field public static final int UNIX_LINES = 1; // 0x1
}
diff --git a/api/removed.txt b/api/removed.txt
index f12e61e..6b7961e 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -199,6 +199,15 @@
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index ee975d1..15fc680 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -93,7 +93,6 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
@@ -2215,22 +2214,6 @@
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_Material = 16974372; // 0x1030224
- field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
- field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
- field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
- field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
- field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
- field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
- field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
- field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
- field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
- field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
- field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
- field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
- field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
- field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2244,7 +2227,7 @@
field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
- field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+ field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -3477,6 +3460,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3624,6 +3608,7 @@
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -3658,6 +3643,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
+ method public void setVrMode(boolean);
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -4215,11 +4201,14 @@
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4359,7 +4348,7 @@
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4971,6 +4960,7 @@
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5137,6 +5127,7 @@
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5326,6 +5317,7 @@
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5779,10 +5771,12 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setDisplayOffset(android.os.IBinder, int, int);
method public void setDisplayPadding(android.graphics.Rect);
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public boolean setWallpaperComponent(android.content.ComponentName);
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
@@ -5878,6 +5872,7 @@
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+ method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5891,8 +5886,11 @@
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
+ method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
+ method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5914,6 +5912,7 @@
method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5927,6 +5926,7 @@
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+ method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5935,6 +5935,7 @@
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void notifyPendingSystemUpdate(long);
+ method public void reboot(android.content.ComponentName);
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
@@ -5944,6 +5945,7 @@
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
+ method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
@@ -5954,9 +5956,11 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
+ method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -5977,6 +5981,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7811,11 +7816,12 @@
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7829,7 +7835,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -8701,6 +8707,8 @@
field public static final int EXTRA_DOCK_STATE_UNDOCKED = 0; // 0x0
field public static final java.lang.String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
field public static final java.lang.String EXTRA_EMAIL = "android.intent.extra.EMAIL";
+ field public static final java.lang.String EXTRA_EPHEMERAL_FAILURE = "android.intent.extra.EPHEMERAL_FAILURE";
+ field public static final java.lang.String EXTRA_EPHEMERAL_SUCCESS = "android.intent.extra.EPHEMERAL_SUCCESS";
field public static final java.lang.String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
field public static final java.lang.String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
field public static final java.lang.String EXTRA_INSTALLER_PACKAGE_NAME = "android.intent.extra.INSTALLER_PACKAGE_NAME";
@@ -8754,6 +8762,7 @@
field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
+ field public static final int FLAG_ACTIVITY_LAUNCH_TO_SIDE = 4096; // 0x1000
field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
@@ -9265,6 +9274,7 @@
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+ field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9360,6 +9370,7 @@
field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+ field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
@@ -9449,6 +9460,18 @@
field protected static final java.lang.String TAG = "ContainerEncryptionParams";
}
+ public final class EphemeralResolveInfo implements android.os.Parcelable {
+ ctor public EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
+ method public int describeContents();
+ method public byte[] getDigestBytes();
+ method public int getDigestPrefix();
+ method public java.util.List<android.content.IntentFilter> getFilters();
+ method public java.lang.String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo> CREATOR;
+ field public static final java.lang.String SHA_ALGORITHM = "SHA-256";
+ }
+
public final class FeatureGroupInfo implements android.os.Parcelable {
ctor public FeatureGroupInfo();
ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo);
@@ -9533,12 +9556,6 @@
method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
}
- public class ManifestDigest implements android.os.Parcelable {
- method public int describeContents();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.content.pm.ManifestDigest> CREATOR;
- }
-
public class PackageInfo implements android.os.Parcelable {
ctor public PackageInfo();
method public int describeContents();
@@ -9647,7 +9664,6 @@
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
method public void setGrantedRuntimePermissions(java.lang.String[]);
- method public void setInstallFlagsQuick();
method public void setInstallLocation(int);
method public void setOriginatingUid(int);
method public void setOriginatingUri(android.net.Uri);
@@ -9732,8 +9748,10 @@
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+ method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.lang.String[] getPackagesForUid(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
@@ -9813,6 +9831,7 @@
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9834,6 +9853,7 @@
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
+ field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
@@ -9863,15 +9883,15 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
- field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9883,7 +9903,7 @@
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
@@ -9924,6 +9944,13 @@
field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+ field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10313,6 +10340,7 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
+ method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -10944,6 +10972,7 @@
method public void setVersion(int);
method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+ method public void validateSql(java.lang.String, android.os.CancellationSignal);
method public deprecated boolean yieldIfContended();
method public boolean yieldIfContendedSafely();
method public boolean yieldIfContendedSafely(long);
@@ -11178,7 +11207,7 @@
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -11188,6 +11217,7 @@
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -11201,7 +11231,7 @@
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11605,14 +11635,14 @@
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -19208,7 +19238,6 @@
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -19232,8 +19261,6 @@
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -19246,8 +19273,6 @@
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -19343,8 +19368,6 @@
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -23783,6 +23806,7 @@
public class TvStreamConfig implements android.os.Parcelable {
method public int describeContents();
+ method public int getFlags();
method public int getGeneration();
method public int getMaxHeight();
method public int getMaxWidth();
@@ -23790,6 +23814,7 @@
method public int getType();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.tv.TvStreamConfig> CREATOR;
+ field public static final int FLAG_MASK_SIGNAL_DETECTION = 1; // 0x1
field public static final int STREAM_TYPE_BUFFER_PRODUCER = 2; // 0x2
field public static final int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1; // 0x1
}
@@ -23797,6 +23822,7 @@
public static final class TvStreamConfig.Builder {
ctor public TvStreamConfig.Builder();
method public android.media.tv.TvStreamConfig build();
+ method public android.media.tv.TvStreamConfig.Builder flags(int);
method public android.media.tv.TvStreamConfig.Builder generation(int);
method public android.media.tv.TvStreamConfig.Builder maxHeight(int);
method public android.media.tv.TvStreamConfig.Builder maxWidth(int);
@@ -23975,6 +24001,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
+ method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -25737,7 +25764,6 @@
method public void writeToParcel(android.os.Parcel, int);
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
- field public int exponent;
field public int maxPeriodInMs;
field public int maxScansToCache;
field public int numBssidsPerScan;
@@ -28832,6 +28858,279 @@
method public abstract void onMessage(int, int, int, int, java.lang.String);
}
+ public class GLES32 extends android.opengl.GLES31 {
+ method public static void glBlendBarrier();
+ method public static void glBlendEquationSeparatei(int, int, int);
+ method public static void glBlendEquationi(int, int);
+ method public static void glBlendFuncSeparatei(int, int, int, int, int);
+ method public static void glBlendFunci(int, int, int);
+ method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+ method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+ method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+ method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+ method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+ method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+ method public static void glDisablei(int, int);
+ method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+ method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+ method public static void glEnablei(int, int);
+ method public static void glFramebufferTexture(int, int, int, int);
+ method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+ method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+ method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+ method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+ method public static int glGetGraphicsResetStatus();
+ method public static java.lang.String glGetObjectLabel(int, int);
+ method public static java.lang.String glGetObjectPtrLabel(long);
+ method public static long glGetPointerv(int);
+ method public static void glGetSamplerParameterIiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIiv(int, int, int[], int);
+ method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIuiv(int, int, int[], int);
+ method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformfv(int, int, int, float[], int);
+ method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+ method public static void glGetnUniformiv(int, int, int, int[], int);
+ method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformuiv(int, int, int, int[], int);
+ method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+ method public static boolean glIsEnabledi(int, int);
+ method public static void glMinSampleShading(float);
+ method public static void glObjectLabel(int, int, int, java.lang.String);
+ method public static void glObjectPtrLabel(long, java.lang.String);
+ method public static void glPatchParameteri(int, int);
+ method public static void glPopDebugGroup();
+ method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+ method public static void glPushDebugGroup(int, int, int, java.lang.String);
+ method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+ method public static void glSamplerParameterIiv(int, int, int[], int);
+ method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glSamplerParameterIuiv(int, int, int[], int);
+ method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexBuffer(int, int, int);
+ method public static void glTexBufferRange(int, int, int, int, int);
+ method public static void glTexParameterIiv(int, int, int[], int);
+ method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glTexParameterIuiv(int, int, int[], int);
+ method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+ field public static final int GL_BUFFER = 33504; // 0x82e0
+ field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+ field public static final int GL_COLORBURN = 37530; // 0x929a
+ field public static final int GL_COLORDODGE = 37529; // 0x9299
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+ field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+ field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+ field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+ field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+ field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+ field public static final int GL_DARKEN = 37527; // 0x9297
+ field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+ field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+ field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+ field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+ field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+ field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+ field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+ field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+ field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+ field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+ field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+ field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+ field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+ field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+ field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+ field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+ field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+ field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+ field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+ field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+ field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+ field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+ field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+ field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+ field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+ field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+ field public static final int GL_DIFFERENCE = 37534; // 0x929e
+ field public static final int GL_EXCLUSION = 37536; // 0x92a0
+ field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+ field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+ field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+ field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+ field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+ field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+ field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+ field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+ field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+ field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+ field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+ field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+ field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+ field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+ field public static final int GL_HARDLIGHT = 37531; // 0x929b
+ field public static final int GL_HSL_COLOR = 37551; // 0x92af
+ field public static final int GL_HSL_HUE = 37549; // 0x92ad
+ field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+ field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+ field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+ field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+ field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+ field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+ field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+ field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+ field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+ field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+ field public static final int GL_ISOLINES = 36474; // 0x8e7a
+ field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+ field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+ field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+ field public static final int GL_LIGHTEN = 37528; // 0x9298
+ field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+ field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+ field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+ field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+ field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+ field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+ field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+ field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+ field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+ field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+ field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+ field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+ field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+ field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+ field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+ field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+ field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+ field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+ field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+ field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+ field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+ field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+ field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+ field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+ field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+ field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+ field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+ field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+ field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+ field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+ field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+ field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+ field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+ field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+ field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+ field public static final int GL_MULTIPLY = 37524; // 0x9294
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+ field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+ field public static final int GL_OVERLAY = 37526; // 0x9296
+ field public static final int GL_PATCHES = 14; // 0xe
+ field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+ field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+ field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+ field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+ field public static final int GL_PROGRAM = 33506; // 0x82e2
+ field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+ field public static final int GL_QUADS = 7; // 0x7
+ field public static final int GL_QUERY = 33507; // 0x82e3
+ field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+ field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+ field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+ field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+ field public static final int GL_SAMPLER = 33510; // 0x82e6
+ field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+ field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+ field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+ field public static final int GL_SCREEN = 37525; // 0x9295
+ field public static final int GL_SHADER = 33505; // 0x82e1
+ field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+ field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+ field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+ field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+ field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+ field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+ field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+ field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+ field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+ field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+ field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+ field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+ field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+ field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+ field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+ field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+ field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+ field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+ field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+ field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+ field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+ field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+ field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+ field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+ field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+ field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+ field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+ field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+ field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+ field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+ }
+
+ public static abstract interface GLES32.DebugProc {
+ method public abstract void onMessage(int, int, int, int, java.lang.String);
+ }
+
public class GLException extends java.lang.RuntimeException {
ctor public GLException(int);
ctor public GLException(int, java.lang.String);
@@ -30864,6 +31163,9 @@
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -30884,6 +31186,10 @@
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -30939,6 +31245,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -31307,6 +31614,7 @@
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
field public static final java.lang.String IS_READ = "is_read";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
field public static final int MISSED_TYPE = 3; // 0x3
field public static final java.lang.String NEW = "new";
@@ -32507,7 +32815,7 @@
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
- field public static final int FLAG_ARCHIVE = 2048; // 0x800
+ field public static final int FLAG_ARCHIVE = 1024; // 0x400
field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
@@ -32516,9 +32824,8 @@
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
- field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
- field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
}
@@ -33047,6 +33354,7 @@
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -33063,6 +33371,7 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
+ field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -33709,6 +34018,7 @@
public static final class VoicemailContract.Status implements android.provider.BaseColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -33725,6 +34035,9 @@
field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+ field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+ field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+ field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -33741,6 +34054,7 @@
field public static final java.lang.String HAS_CONTENT = "has_content";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -34932,6 +35246,7 @@
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -35347,6 +35662,7 @@
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
public class NotificationAssistantService.Adjustment {
@@ -35381,6 +35697,7 @@
method public final void setNotificationsShown(java.lang.String[]);
method public final void setOnNotificationPostedTrim(int);
method public void unregisterAsSystemService() throws android.os.RemoteException;
+ field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -35390,6 +35707,7 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public static final int TRIM_FULL = 0; // 0x0
field public static final int TRIM_LIGHT = 1; // 0x1
}
@@ -35488,10 +35806,13 @@
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -36795,6 +37116,7 @@
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
@@ -38763,7 +39085,6 @@
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -38775,8 +39096,10 @@
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInstaller getPackageInstaller();
+ method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.String[] getPackagesForUid(int);
method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
@@ -38819,7 +39142,6 @@
method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle);
@@ -41211,7 +41533,7 @@
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -41642,7 +41964,6 @@
method public int getAction();
method public android.content.ClipData getClipData();
method public android.content.ClipDescription getClipDescription();
- method public android.view.DropPermissionHolder getDropPermissionHolder();
method public java.lang.Object getLocalState();
method public boolean getResult();
method public float getX();
@@ -41657,12 +41978,8 @@
field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
}
- public class DropPermissionHolder implements android.os.Parcelable {
- method public int describeContents();
- method public void grant();
- method public void revoke();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+ public final class DropPermissions {
+ method public void release();
}
public class FocusFinder {
@@ -42588,6 +42905,8 @@
field public static final int AXIS_LTRIGGER = 17; // 0x11
field public static final int AXIS_ORIENTATION = 8; // 0x8
field public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
field public static final int AXIS_RTRIGGER = 18; // 0x12
field public static final int AXIS_RUDDER = 20; // 0x14
field public static final int AXIS_RX = 12; // 0xc
@@ -43123,6 +43442,7 @@
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -43249,6 +43569,7 @@
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -43349,6 +43670,7 @@
method public void setPaddingRelative(int, int, int, int);
method public void setPivotX(float);
method public void setPivotY(float);
+ method public void setPointerCapture();
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
method public final void setRight(int);
@@ -62076,8 +62398,8 @@
method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
method public int end();
method public int end(int);
- method public boolean find(int);
method public boolean find();
+ method public boolean find(int);
method public java.lang.String group();
method public java.lang.String group(int);
method public int groupCount();
@@ -62105,8 +62427,8 @@
}
public final class Pattern implements java.io.Serializable {
- method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public static java.util.regex.Pattern compile(java.lang.String);
+ method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public int flags();
method public java.util.regex.Matcher matcher(java.lang.CharSequence);
method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -62121,6 +62443,7 @@
field public static final int LITERAL = 16; // 0x10
field public static final int MULTILINE = 8; // 0x8
field public static final int UNICODE_CASE = 64; // 0x40
+ field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
field public static final int UNIX_LINES = 1; // 0x1
}
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 642d2a8..90a5dc7 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -190,6 +190,15 @@
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/api/test-current.txt b/api/test-current.txt
index c494895..4a2641f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -67,7 +67,6 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -2114,22 +2113,6 @@
field public static final int Theme_Light_Panel = 16973914; // 0x103005a
field public static final int Theme_Light_WallpaperSettings = 16973922; // 0x1030062
field public static final int Theme_Material = 16974372; // 0x1030224
- field public static final int Theme_Material_DayNight = 16974552; // 0x10302d8
- field public static final int Theme_Material_DayNight_DarkActionBar = 16974553; // 0x10302d9
- field public static final int Theme_Material_DayNight_Dialog = 16974554; // 0x10302da
- field public static final int Theme_Material_DayNight_DialogWhenLarge = 16974560; // 0x10302e0
- field public static final int Theme_Material_DayNight_DialogWhenLarge_DarkActionBar = 16974568; // 0x10302e8
- field public static final int Theme_Material_DayNight_DialogWhenLarge_NoActionBar = 16974561; // 0x10302e1
- field public static final int Theme_Material_DayNight_Dialog_Alert = 16974555; // 0x10302db
- field public static final int Theme_Material_DayNight_Dialog_MinWidth = 16974556; // 0x10302dc
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar = 16974557; // 0x10302dd
- field public static final int Theme_Material_DayNight_Dialog_NoActionBar_MinWidth = 16974558; // 0x10302de
- field public static final int Theme_Material_DayNight_Dialog_Presentation = 16974559; // 0x10302df
- field public static final int Theme_Material_DayNight_NoActionBar = 16974562; // 0x10302e2
- field public static final int Theme_Material_DayNight_NoActionBar_Fullscreen = 16974563; // 0x10302e3
- field public static final int Theme_Material_DayNight_NoActionBar_Overscan = 16974564; // 0x10302e4
- field public static final int Theme_Material_DayNight_NoActionBar_TranslucentDecor = 16974565; // 0x10302e5
- field public static final int Theme_Material_DayNight_Panel = 16974566; // 0x10302e6
field public static final int Theme_Material_Dialog = 16974373; // 0x1030225
field public static final int Theme_Material_DialogWhenLarge = 16974379; // 0x103022b
field public static final int Theme_Material_DialogWhenLarge_NoActionBar = 16974380; // 0x103022c
@@ -2143,7 +2126,7 @@
field public static final int Theme_Material_Light_DarkActionBar = 16974392; // 0x1030238
field public static final int Theme_Material_Light_Dialog = 16974393; // 0x1030239
field public static final int Theme_Material_Light_DialogWhenLarge = 16974399; // 0x103023f
- field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974567; // 0x10302e7
+ field public static final int Theme_Material_Light_DialogWhenLarge_DarkActionBar = 16974552; // 0x10302d8
field public static final int Theme_Material_Light_DialogWhenLarge_NoActionBar = 16974400; // 0x1030240
field public static final int Theme_Material_Light_Dialog_Alert = 16974394; // 0x103023a
field public static final int Theme_Material_Light_Dialog_MinWidth = 16974395; // 0x103023b
@@ -3374,6 +3357,7 @@
method public boolean dispatchTouchEvent(android.view.MotionEvent);
method public boolean dispatchTrackballEvent(android.view.MotionEvent);
method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+ method public void enterPictureInPictureMode();
method public android.view.View findViewById(int);
method public void finish();
method public void finishActivity(int);
@@ -3519,6 +3503,7 @@
method public boolean releaseInstance();
method public final deprecated void removeDialog(int);
method public void reportFullyDrawn();
+ method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
method public final void requestPermissions(java.lang.String[], int);
method public boolean requestVisibleBehind(boolean);
method public final boolean requestWindowFeature(int);
@@ -3553,6 +3538,7 @@
method public deprecated void setTitleColor(int);
method public void setVisible(boolean);
method public final void setVolumeControlStream(int);
+ method public void setVrMode(boolean);
method public boolean shouldShowRequestPermissionRationale(java.lang.String);
method public boolean shouldUpRecreateTask(android.content.Intent);
method public boolean showAssist(android.os.Bundle);
@@ -4095,11 +4081,14 @@
}
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
+ ctor public DatePickerDialog(android.content.Context);
+ ctor public DatePickerDialog(android.content.Context, int);
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
method public android.widget.DatePicker getDatePicker();
method public void onClick(android.content.DialogInterface, int);
method public void onDateChanged(android.widget.DatePicker, int, int, int);
+ method public void setOnDateSetListener(android.app.DatePickerDialog.OnDateSetListener);
method public void updateDate(int, int, int);
}
@@ -4239,7 +4228,7 @@
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_ID = "_id";
field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
- field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+ field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -4851,6 +4840,7 @@
field public static final java.lang.String EXTRA_PROGRESS = "android.progress";
field public static final java.lang.String EXTRA_PROGRESS_INDETERMINATE = "android.progressIndeterminate";
field public static final java.lang.String EXTRA_PROGRESS_MAX = "android.progressMax";
+ field public static final java.lang.String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
@@ -5017,6 +5007,7 @@
method public android.app.Notification.Builder setPriority(int);
method public android.app.Notification.Builder setProgress(int, int, boolean);
method public android.app.Notification.Builder setPublicVersion(android.app.Notification);
+ method public android.app.Notification.Builder setRemoteInputHistory(java.lang.CharSequence[]);
method public android.app.Notification.Builder setShowWhen(boolean);
method public android.app.Notification.Builder setSmallIcon(int);
method public android.app.Notification.Builder setSmallIcon(int, int);
@@ -5206,6 +5197,7 @@
field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
field public final int priorityCallSenders;
field public final int priorityCategories;
field public final int priorityMessageSenders;
@@ -5509,8 +5501,10 @@
method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
+ method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean injectInputEvent(android.view.InputEvent, boolean);
method public final boolean performGlobalAction(int);
+ method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
method public boolean setRotation(int);
method public void setRunAsMonkey(boolean);
@@ -5658,8 +5652,10 @@
method public android.graphics.drawable.Drawable peekFastDrawable();
method public void sendWallpaperCommand(android.os.IBinder, java.lang.String, int, int, int, android.os.Bundle);
method public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
+ method public void setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setResource(int) throws java.io.IOException;
method public void setStream(java.io.InputStream) throws java.io.IOException;
+ method public void setStream(java.io.InputStream, android.graphics.Rect, boolean) throws java.io.IOException;
method public void setWallpaperOffsetSteps(float, float);
method public void setWallpaperOffsets(android.os.IBinder, float, float);
method public void suggestDesiredDimensions(int, int);
@@ -5753,6 +5749,7 @@
method public java.lang.String[] getAccountTypesWithManagementDisabled();
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
+ method public java.lang.String getApplicationRestrictionsManagingPackage(android.content.ComponentName);
method public boolean getAutoTimeRequired();
method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
method public boolean getCameraDisabled(android.content.ComponentName);
@@ -5763,8 +5760,11 @@
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
+ method public java.lang.String getLongSupportMessage(android.content.ComponentName);
method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
method public long getMaximumTimeToLock(android.content.ComponentName);
+ method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
+ method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
method public long getPasswordExpiration(android.content.ComponentName);
method public long getPasswordExpirationTimeout(android.content.ComponentName);
method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5782,6 +5782,7 @@
method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
method public boolean getScreenCaptureDisabled(android.content.ComponentName);
+ method public java.lang.String getShortSupportMessage(android.content.ComponentName);
method public boolean getStorageEncryption(android.content.ComponentName);
method public int getStorageEncryptionStatus();
method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5795,6 +5796,7 @@
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
+ method public boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5802,6 +5804,7 @@
method public boolean isProvisioningAllowed(java.lang.String);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
+ method public void reboot(android.content.ComponentName);
method public void removeActiveAdmin(android.content.ComponentName);
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeKeyPair(android.content.ComponentName, java.lang.String);
@@ -5810,6 +5813,7 @@
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
+ method public void setApplicationRestrictionsManagingPackage(android.content.ComponentName, java.lang.String);
method public void setAutoTimeRequired(android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
method public void setCameraDisabled(android.content.ComponentName, boolean);
@@ -5820,9 +5824,11 @@
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
method public void setMaximumTimeToLock(android.content.ComponentName, long);
+ method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
method public void setPasswordHistoryLength(android.content.ComponentName, int);
method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -5843,6 +5849,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -7568,11 +7575,12 @@
method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
}
- public class ContentProviderClient {
+ public class ContentProviderClient implements java.lang.AutoCloseable {
method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+ method public void close();
method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
method public android.content.ContentProvider getLocalContentProvider();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7586,7 +7594,7 @@
method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
- method public boolean release();
+ method public deprecated boolean release();
method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
}
@@ -7668,6 +7676,7 @@
method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String);
method public java.util.List<android.content.UriPermission> getPersistedUriPermissions();
method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String);
+ method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int);
method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String);
method public final java.lang.String getType(android.net.Uri);
@@ -7834,6 +7843,7 @@
method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
+ method public abstract int getUserId();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
method public abstract deprecated int getWallpaperDesiredMinimumHeight();
method public abstract deprecated int getWallpaperDesiredMinimumWidth();
@@ -8016,6 +8026,7 @@
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
+ method public int getUserId();
method public deprecated android.graphics.drawable.Drawable getWallpaper();
method public deprecated int getWallpaperDesiredMinimumHeight();
method public deprecated int getWallpaperDesiredMinimumWidth();
@@ -8488,6 +8499,7 @@
field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
+ field public static final int FLAG_ACTIVITY_LAUNCH_TO_SIDE = 4096; // 0x1000
field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
@@ -8999,6 +9011,7 @@
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
+ field public static final int FLAG_ENABLE_VR_MODE = 32768; // 0x8000
field public static final int FLAG_EXCLUDE_FROM_RECENTS = 32; // 0x20
field public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 256; // 0x100
field public static final int FLAG_FINISH_ON_TASK_LAUNCH = 2; // 0x2
@@ -9066,6 +9079,8 @@
ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
+ method public boolean isPrivilegedApp();
+ method public boolean isSystemApp();
method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR;
field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000
@@ -9094,6 +9109,7 @@
field public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 8192; // 0x2000
field public static final int FLAG_SUPPORTS_SMALL_SCREENS = 512; // 0x200
field public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 524288; // 0x80000
+ field public static final int FLAG_SUSPENDED = 1073741824; // 0x40000000
field public static final int FLAG_SYSTEM = 1; // 0x1
field public static final int FLAG_TEST_ONLY = 256; // 0x100
field public static final int FLAG_UPDATED_SYSTEM_APP = 128; // 0x80
@@ -9426,6 +9442,7 @@
method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getComponentEnabledSetting(android.content.ComponentName);
method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+ method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public abstract byte[] getEphemeralCookie();
method public abstract int getEphemeralCookieMaxSizeBytes();
@@ -9438,8 +9455,10 @@
method public abstract java.lang.String getNameForUid(int);
method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int);
method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.pm.PackageInstaller getPackageInstaller();
+ method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract java.lang.String[] getPackagesForUid(int);
method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -9510,6 +9529,7 @@
field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+ field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9531,6 +9551,7 @@
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
+ field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
@@ -9560,15 +9581,15 @@
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+ field public static final java.lang.String FEATURE_VR_MODE = "android.software.vr.mode";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
- field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
- field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
- field public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 262144; // 0x40000
+ field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
field public static final int GET_GIDS = 256; // 0x100
field public static final int GET_INSTRUMENTATION = 16; // 0x10
field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9580,10 +9601,17 @@
field public static final int GET_SERVICES = 4; // 0x4
field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
field public static final int GET_SIGNATURES = 64; // 0x40
- field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+ field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
field public static final int MATCH_ALL = 131072; // 0x20000
field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+ field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+ field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+ field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
+ field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
+ field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+ field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+ field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
field public static final int PERMISSION_DENIED = -1; // 0xffffffff
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -9966,6 +9994,7 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
+ method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -10597,6 +10626,7 @@
method public void setVersion(int);
method public int update(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[]);
method public int updateWithOnConflict(java.lang.String, android.content.ContentValues, java.lang.String, java.lang.String[], int);
+ method public void validateSql(java.lang.String, android.os.CancellationSignal);
method public deprecated boolean yieldIfContended();
method public boolean yieldIfContendedSafely();
method public boolean yieldIfContendedSafely(long);
@@ -10831,7 +10861,7 @@
field public final int statusCode;
}
- public class DrmManagerClient {
+ public class DrmManagerClient implements java.lang.AutoCloseable {
ctor public DrmManagerClient(android.content.Context);
method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10841,6 +10871,7 @@
method public int checkRightsStatus(android.net.Uri);
method public int checkRightsStatus(java.lang.String, int);
method public int checkRightsStatus(android.net.Uri, int);
+ method public void close();
method public android.drm.DrmConvertedStatus closeConvertSession(int);
method public android.drm.DrmConvertedStatus convertData(int, byte[]);
method public java.lang.String[] getAvailableDrmEngines();
@@ -10854,7 +10885,7 @@
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
- method public void release();
+ method public deprecated void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);
@@ -11258,14 +11289,14 @@
public static class BitmapFactory.Options {
ctor public BitmapFactory.Options();
- method public void requestCancelDecode();
+ method public deprecated void requestCancelDecode();
field public android.graphics.Bitmap inBitmap;
field public int inDensity;
- field public boolean inDither;
+ field public deprecated boolean inDither;
field public deprecated boolean inInputShareable;
field public boolean inJustDecodeBounds;
field public boolean inMutable;
- field public boolean inPreferQualityOverSpeed;
+ field public deprecated boolean inPreferQualityOverSpeed;
field public android.graphics.Bitmap.Config inPreferredConfig;
field public boolean inPremultiplied;
field public deprecated boolean inPurgeable;
@@ -18234,7 +18265,6 @@
method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
method public int getDSTSavings();
method public static android.icu.util.TimeZone getDefault();
- method public static int getDefaultTimeZoneType();
method public final java.lang.String getDisplayName();
method public final java.lang.String getDisplayName(java.util.Locale);
method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18258,8 +18288,6 @@
method public abstract boolean inDaylightTime(java.util.Date);
method public boolean isFrozen();
method public boolean observesDaylightTime();
- method public static synchronized void setDefault(android.icu.util.TimeZone);
- method public static synchronized void setDefaultTimeZoneType(int);
method public void setID(java.lang.String);
method public abstract void setRawOffset(int);
method public abstract boolean useDaylightTime();
@@ -18272,8 +18300,6 @@
field public static final int SHORT_COMMONLY_USED = 6; // 0x6
field public static final int SHORT_GENERIC = 2; // 0x2
field public static final int SHORT_GMT = 4; // 0x4
- field public static final int TIMEZONE_ICU = 0; // 0x0
- field public static final int TIMEZONE_JDK = 1; // 0x1
field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
}
@@ -18369,8 +18395,6 @@
method public static java.lang.String getVariant(java.lang.String);
method public boolean isRightToLeft();
method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale);
- method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String toLanguageTag();
@@ -22439,6 +22463,7 @@
method public int[] getObjectHandles(int, int, int);
method public android.mtp.MtpObjectInfo getObjectInfo(int);
method public long getParent(int);
+ method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException;
method public long getStorageId(int);
method public int[] getStorageIds();
method public android.mtp.MtpStorageInfo getStorageInfo(int);
@@ -26851,6 +26876,279 @@
method public abstract void onMessage(int, int, int, int, java.lang.String);
}
+ public class GLES32 extends android.opengl.GLES31 {
+ method public static void glBlendBarrier();
+ method public static void glBlendEquationSeparatei(int, int, int);
+ method public static void glBlendEquationi(int, int);
+ method public static void glBlendFuncSeparatei(int, int, int, int, int);
+ method public static void glBlendFunci(int, int, int);
+ method public static void glColorMaski(int, boolean, boolean, boolean, boolean);
+ method public static void glCopyImageSubData(int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
+ method public static void glDebugMessageCallback(android.opengl.GLES32.DebugProc);
+ method public static void glDebugMessageControl(int, int, int, int, int[], int, boolean);
+ method public static void glDebugMessageControl(int, int, int, int, java.nio.IntBuffer, boolean);
+ method public static void glDebugMessageInsert(int, int, int, int, int, java.lang.String);
+ method public static void glDisablei(int, int);
+ method public static void glDrawElementsBaseVertex(int, int, int, java.nio.Buffer, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, java.nio.Buffer, int, int);
+ method public static void glDrawElementsInstancedBaseVertex(int, int, int, int, int, int);
+ method public static void glDrawRangeElementsBaseVertex(int, int, int, int, int, java.nio.Buffer, int);
+ method public static void glEnablei(int, int);
+ method public static void glFramebufferTexture(int, int, int, int);
+ method public static int glGetDebugMessageLog(int, int, int[], int, int[], int, int[], int, int[], int, int[], int, byte[], int);
+ method public static int glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
+ method public static java.lang.String[] glGetDebugMessageLog(int, int[], int, int[], int, int[], int, int[], int);
+ method public static java.lang.String[] glGetDebugMessageLog(int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer);
+ method public static int glGetGraphicsResetStatus();
+ method public static java.lang.String glGetObjectLabel(int, int);
+ method public static java.lang.String glGetObjectPtrLabel(long);
+ method public static long glGetPointerv(int);
+ method public static void glGetSamplerParameterIiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetSamplerParameterIuiv(int, int, int[], int);
+ method public static void glGetSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIiv(int, int, int[], int);
+ method public static void glGetTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glGetTexParameterIuiv(int, int, int[], int);
+ method public static void glGetTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformfv(int, int, int, float[], int);
+ method public static void glGetnUniformfv(int, int, int, java.nio.FloatBuffer);
+ method public static void glGetnUniformiv(int, int, int, int[], int);
+ method public static void glGetnUniformiv(int, int, int, java.nio.IntBuffer);
+ method public static void glGetnUniformuiv(int, int, int, int[], int);
+ method public static void glGetnUniformuiv(int, int, int, java.nio.IntBuffer);
+ method public static boolean glIsEnabledi(int, int);
+ method public static void glMinSampleShading(float);
+ method public static void glObjectLabel(int, int, int, java.lang.String);
+ method public static void glObjectPtrLabel(long, java.lang.String);
+ method public static void glPatchParameteri(int, int);
+ method public static void glPopDebugGroup();
+ method public static void glPrimitiveBoundingBox(float, float, float, float, float, float, float, float);
+ method public static void glPushDebugGroup(int, int, int, java.lang.String);
+ method public static void glReadnPixels(int, int, int, int, int, int, int, java.nio.Buffer);
+ method public static void glSamplerParameterIiv(int, int, int[], int);
+ method public static void glSamplerParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glSamplerParameterIuiv(int, int, int[], int);
+ method public static void glSamplerParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexBuffer(int, int, int);
+ method public static void glTexBufferRange(int, int, int, int, int);
+ method public static void glTexParameterIiv(int, int, int[], int);
+ method public static void glTexParameterIiv(int, int, java.nio.IntBuffer);
+ method public static void glTexParameterIuiv(int, int, int[], int);
+ method public static void glTexParameterIuiv(int, int, java.nio.IntBuffer);
+ method public static void glTexStorage3DMultisample(int, int, int, int, int, int, boolean);
+ field public static final int GL_BUFFER = 33504; // 0x82e0
+ field public static final int GL_CLAMP_TO_BORDER = 33069; // 0x812d
+ field public static final int GL_COLORBURN = 37530; // 0x929a
+ field public static final int GL_COLORDODGE = 37529; // 0x9299
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 37819; // 0x93bb
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 37816; // 0x93b8
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 37817; // 0x93b9
+ field public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 37818; // 0x93ba
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 37820; // 0x93bc
+ field public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 37821; // 0x93bd
+ field public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 37808; // 0x93b0
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 37809; // 0x93b1
+ field public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 37810; // 0x93b2
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 37811; // 0x93b3
+ field public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 37812; // 0x93b4
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 37813; // 0x93b5
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 37814; // 0x93b6
+ field public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 37815; // 0x93b7
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 37851; // 0x93db
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 37848; // 0x93d8
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 37849; // 0x93d9
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 37850; // 0x93da
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 37852; // 0x93dc
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 37853; // 0x93dd
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 37840; // 0x93d0
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 37841; // 0x93d1
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 37842; // 0x93d2
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 37843; // 0x93d3
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 37844; // 0x93d4
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 37845; // 0x93d5
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 37846; // 0x93d6
+ field public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 37847; // 0x93d7
+ field public static final int GL_CONTEXT_FLAGS = 33310; // 0x821e
+ field public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 2; // 0x2
+ field public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 4; // 0x4
+ field public static final int GL_CONTEXT_LOST = 1287; // 0x507
+ field public static final int GL_DARKEN = 37527; // 0x9297
+ field public static final int GL_DEBUG_CALLBACK_FUNCTION = 33348; // 0x8244
+ field public static final int GL_DEBUG_CALLBACK_USER_PARAM = 33349; // 0x8245
+ field public static final int GL_DEBUG_GROUP_STACK_DEPTH = 33389; // 0x826d
+ field public static final int GL_DEBUG_LOGGED_MESSAGES = 37189; // 0x9145
+ field public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 33347; // 0x8243
+ field public static final int GL_DEBUG_OUTPUT = 37600; // 0x92e0
+ field public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 33346; // 0x8242
+ field public static final int GL_DEBUG_SEVERITY_HIGH = 37190; // 0x9146
+ field public static final int GL_DEBUG_SEVERITY_LOW = 37192; // 0x9148
+ field public static final int GL_DEBUG_SEVERITY_MEDIUM = 37191; // 0x9147
+ field public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 33387; // 0x826b
+ field public static final int GL_DEBUG_SOURCE_API = 33350; // 0x8246
+ field public static final int GL_DEBUG_SOURCE_APPLICATION = 33354; // 0x824a
+ field public static final int GL_DEBUG_SOURCE_OTHER = 33355; // 0x824b
+ field public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 33352; // 0x8248
+ field public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 33353; // 0x8249
+ field public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 33351; // 0x8247
+ field public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 33357; // 0x824d
+ field public static final int GL_DEBUG_TYPE_ERROR = 33356; // 0x824c
+ field public static final int GL_DEBUG_TYPE_MARKER = 33384; // 0x8268
+ field public static final int GL_DEBUG_TYPE_OTHER = 33361; // 0x8251
+ field public static final int GL_DEBUG_TYPE_PERFORMANCE = 33360; // 0x8250
+ field public static final int GL_DEBUG_TYPE_POP_GROUP = 33386; // 0x826a
+ field public static final int GL_DEBUG_TYPE_PORTABILITY = 33359; // 0x824f
+ field public static final int GL_DEBUG_TYPE_PUSH_GROUP = 33385; // 0x8269
+ field public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 33358; // 0x824e
+ field public static final int GL_DIFFERENCE = 37534; // 0x929e
+ field public static final int GL_EXCLUSION = 37536; // 0x92a0
+ field public static final int GL_FIRST_VERTEX_CONVENTION = 36429; // 0x8e4d
+ field public static final int GL_FRACTIONAL_EVEN = 36476; // 0x8e7c
+ field public static final int GL_FRACTIONAL_ODD = 36475; // 0x8e7b
+ field public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 36445; // 0x8e5d
+ field public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 36263; // 0x8da7
+ field public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 37650; // 0x9312
+ field public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 36264; // 0x8da8
+ field public static final int GL_GEOMETRY_INPUT_TYPE = 35095; // 0x8917
+ field public static final int GL_GEOMETRY_OUTPUT_TYPE = 35096; // 0x8918
+ field public static final int GL_GEOMETRY_SHADER = 36313; // 0x8dd9
+ field public static final int GL_GEOMETRY_SHADER_BIT = 4; // 0x4
+ field public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 34943; // 0x887f
+ field public static final int GL_GEOMETRY_VERTICES_OUT = 35094; // 0x8916
+ field public static final int GL_GUILTY_CONTEXT_RESET = 33363; // 0x8253
+ field public static final int GL_HARDLIGHT = 37531; // 0x929b
+ field public static final int GL_HSL_COLOR = 37551; // 0x92af
+ field public static final int GL_HSL_HUE = 37549; // 0x92ad
+ field public static final int GL_HSL_LUMINOSITY = 37552; // 0x92b0
+ field public static final int GL_HSL_SATURATION = 37550; // 0x92ae
+ field public static final int GL_IMAGE_BUFFER = 36945; // 0x9051
+ field public static final int GL_IMAGE_CUBE_MAP_ARRAY = 36948; // 0x9054
+ field public static final int GL_INNOCENT_CONTEXT_RESET = 33364; // 0x8254
+ field public static final int GL_INT_IMAGE_BUFFER = 36956; // 0x905c
+ field public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 36959; // 0x905f
+ field public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37132; // 0x910c
+ field public static final int GL_INT_SAMPLER_BUFFER = 36304; // 0x8dd0
+ field public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 36878; // 0x900e
+ field public static final int GL_ISOLINES = 36474; // 0x8e7a
+ field public static final int GL_IS_PER_PATCH = 37607; // 0x92e7
+ field public static final int GL_LAST_VERTEX_CONVENTION = 36430; // 0x8e4e
+ field public static final int GL_LAYER_PROVOKING_VERTEX = 33374; // 0x825e
+ field public static final int GL_LIGHTEN = 37528; // 0x9298
+ field public static final int GL_LINES_ADJACENCY = 10; // 0xa
+ field public static final int GL_LINE_STRIP_ADJACENCY = 11; // 0xb
+ field public static final int GL_LOSE_CONTEXT_ON_RESET = 33362; // 0x8252
+ field public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 35378; // 0x8a32
+ field public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 36382; // 0x8e1e
+ field public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 36383; // 0x8e1f
+ field public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 33388; // 0x826c
+ field public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 37188; // 0x9144
+ field public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 37187; // 0x9143
+ field public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 36444; // 0x8e5c
+ field public static final int GL_MAX_FRAMEBUFFER_LAYERS = 37655; // 0x9317
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 37589; // 0x92d5
+ field public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 37583; // 0x92cf
+ field public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 37069; // 0x90cd
+ field public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 37155; // 0x9123
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 37156; // 0x9124
+ field public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 36320; // 0x8de0
+ field public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 36442; // 0x8e5a
+ field public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 37079; // 0x90d7
+ field public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 35881; // 0x8c29
+ field public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 36321; // 0x8de1
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 35372; // 0x8a2c
+ field public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 36319; // 0x8ddf
+ field public static final int GL_MAX_LABEL_LENGTH = 33512; // 0x82e8
+ field public static final int GL_MAX_PATCH_VERTICES = 36477; // 0x8e7d
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 37587; // 0x92d3
+ field public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 37581; // 0x92cd
+ field public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 37067; // 0x90cb
+ field public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 34924; // 0x886c
+ field public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 36483; // 0x8e83
+ field public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 37080; // 0x90d8
+ field public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 36481; // 0x8e81
+ field public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 36485; // 0x8e85
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 36489; // 0x8e89
+ field public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 36479; // 0x8e7f
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 37588; // 0x92d4
+ field public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 37582; // 0x92ce
+ field public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 37068; // 0x90cc
+ field public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 34925; // 0x886d
+ field public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 36486; // 0x8e86
+ field public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 37081; // 0x90d9
+ field public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 36482; // 0x8e82
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 36490; // 0x8e8a
+ field public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 36480; // 0x8e80
+ field public static final int GL_MAX_TESS_GEN_LEVEL = 36478; // 0x8e7e
+ field public static final int GL_MAX_TESS_PATCH_COMPONENTS = 36484; // 0x8e84
+ field public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 35883; // 0x8c2b
+ field public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 36443; // 0x8e5b
+ field public static final int GL_MIN_SAMPLE_SHADING_VALUE = 35895; // 0x8c37
+ field public static final int GL_MULTIPLY = 37524; // 0x9294
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 37762; // 0x9382
+ field public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 37761; // 0x9381
+ field public static final int GL_NO_RESET_NOTIFICATION = 33377; // 0x8261
+ field public static final int GL_OVERLAY = 37526; // 0x9296
+ field public static final int GL_PATCHES = 14; // 0xe
+ field public static final int GL_PATCH_VERTICES = 36466; // 0x8e72
+ field public static final int GL_PRIMITIVES_GENERATED = 35975; // 0x8c87
+ field public static final int GL_PRIMITIVE_BOUNDING_BOX = 37566; // 0x92be
+ field public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 33313; // 0x8221
+ field public static final int GL_PROGRAM = 33506; // 0x82e2
+ field public static final int GL_PROGRAM_PIPELINE = 33508; // 0x82e4
+ field public static final int GL_QUADS = 7; // 0x7
+ field public static final int GL_QUERY = 33507; // 0x82e3
+ field public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 37641; // 0x9309
+ field public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 37639; // 0x9307
+ field public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 37640; // 0x9308
+ field public static final int GL_RESET_NOTIFICATION_STRATEGY = 33366; // 0x8256
+ field public static final int GL_SAMPLER = 33510; // 0x82e6
+ field public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 37131; // 0x910b
+ field public static final int GL_SAMPLER_BUFFER = 36290; // 0x8dc2
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 36876; // 0x900c
+ field public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 36877; // 0x900d
+ field public static final int GL_SAMPLE_SHADING = 35894; // 0x8c36
+ field public static final int GL_SCREEN = 37525; // 0x9295
+ field public static final int GL_SHADER = 33505; // 0x82e1
+ field public static final int GL_SOFTLIGHT = 37532; // 0x929c
+ field public static final int GL_STACK_OVERFLOW = 1283; // 0x503
+ field public static final int GL_STACK_UNDERFLOW = 1284; // 0x504
+ field public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 36469; // 0x8e75
+ field public static final int GL_TESS_CONTROL_SHADER = 36488; // 0x8e88
+ field public static final int GL_TESS_CONTROL_SHADER_BIT = 8; // 0x8
+ field public static final int GL_TESS_EVALUATION_SHADER = 36487; // 0x8e87
+ field public static final int GL_TESS_EVALUATION_SHADER_BIT = 16; // 0x10
+ field public static final int GL_TESS_GEN_MODE = 36470; // 0x8e76
+ field public static final int GL_TESS_GEN_POINT_MODE = 36473; // 0x8e79
+ field public static final int GL_TESS_GEN_SPACING = 36471; // 0x8e77
+ field public static final int GL_TESS_GEN_VERTEX_ORDER = 36472; // 0x8e78
+ field public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 37122; // 0x9102
+ field public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 37125; // 0x9105
+ field public static final int GL_TEXTURE_BINDING_BUFFER = 35884; // 0x8c2c
+ field public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 36874; // 0x900a
+ field public static final int GL_TEXTURE_BORDER_COLOR = 4100; // 0x1004
+ field public static final int GL_TEXTURE_BUFFER = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_BINDING = 35882; // 0x8c2a
+ field public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 35885; // 0x8c2d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET = 37277; // 0x919d
+ field public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 37279; // 0x919f
+ field public static final int GL_TEXTURE_BUFFER_SIZE = 37278; // 0x919e
+ field public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 36873; // 0x9009
+ field public static final int GL_TRIANGLES_ADJACENCY = 12; // 0xc
+ field public static final int GL_TRIANGLE_STRIP_ADJACENCY = 13; // 0xd
+ field public static final int GL_UNDEFINED_VERTEX = 33376; // 0x8260
+ field public static final int GL_UNKNOWN_CONTEXT_RESET = 33365; // 0x8255
+ field public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 36967; // 0x9067
+ field public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 36970; // 0x906a
+ field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 37133; // 0x910d
+ field public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 36312; // 0x8dd8
+ field public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 36879; // 0x900f
+ field public static final int GL_VERTEX_ARRAY = 32884; // 0x8074
+ }
+
+ public static abstract interface GLES32.DebugProc {
+ method public abstract void onMessage(int, int, int, int, java.lang.String);
+ }
+
public class GLException extends java.lang.RuntimeException {
ctor public GLException(int);
ctor public GLException(int, java.lang.String);
@@ -28080,6 +28378,7 @@
public final class UserHandle implements android.os.Parcelable {
ctor public UserHandle(android.os.Parcel);
method public int describeContents();
+ method public static int getAppId(int);
method public static android.os.UserHandle readFromParcel(android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -28859,6 +29158,7 @@
method public android.print.PrinterId getId();
method public java.lang.String getName();
method public int getStatus();
+ method public android.graphics.drawable.Drawable loadIcon(android.content.Context);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrinterInfo> CREATOR;
field public static final int STATUS_BUSY = 2; // 0x2
@@ -28872,6 +29172,9 @@
method public android.print.PrinterInfo build();
method public android.print.PrinterInfo.Builder setCapabilities(android.print.PrinterCapabilitiesInfo);
method public android.print.PrinterInfo.Builder setDescription(java.lang.String);
+ method public android.print.PrinterInfo.Builder setHasCustomPrinterIcon();
+ method public android.print.PrinterInfo.Builder setIconResourceId(int);
+ method public android.print.PrinterInfo.Builder setInfoIntent(android.app.PendingIntent);
method public android.print.PrinterInfo.Builder setName(java.lang.String);
method public android.print.PrinterInfo.Builder setStatus(int);
}
@@ -28892,6 +29195,10 @@
package android.printservice {
+ public class CustomPrinterIconCallback {
+ method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
+ }
+
public final class PrintDocument {
method public android.os.ParcelFileDescriptor getData();
method public android.print.PrintDocumentInfo getInfo();
@@ -28947,6 +29254,7 @@
method public final boolean isDestroyed();
method public final boolean isPrinterDiscoveryStarted();
method public abstract void onDestroy();
+ method public void onRequestCustomPrinterIcon(android.print.PrinterId, android.printservice.CustomPrinterIconCallback);
method public abstract void onStartPrinterDiscovery(java.util.List<android.print.PrinterId>);
method public abstract void onStartPrinterStateTracking(android.print.PrinterId);
method public abstract void onStopPrinterDiscovery();
@@ -29315,6 +29623,7 @@
field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
field public static final int INCOMING_TYPE = 1; // 0x1
field public static final java.lang.String IS_READ = "is_read";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String LIMIT_PARAM_KEY = "limit";
field public static final int MISSED_TYPE = 3; // 0x3
field public static final java.lang.String NEW = "new";
@@ -30485,7 +30794,7 @@
field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
field public static final java.lang.String COLUMN_SIZE = "_size";
field public static final java.lang.String COLUMN_SUMMARY = "summary";
- field public static final int FLAG_ARCHIVE = 2048; // 0x800
+ field public static final int FLAG_ARCHIVE = 1024; // 0x400
field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
@@ -30494,9 +30803,8 @@
field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100
field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40
field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
- field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200
field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
- field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400
+ field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
}
@@ -30923,6 +31231,7 @@
field public static final java.lang.String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
+ field public static final java.lang.String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
field public static final java.lang.String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
field public static final java.lang.String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
field public static final java.lang.String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
@@ -30939,6 +31248,7 @@
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
+ field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -31093,6 +31403,7 @@
field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults";
field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
+ field public static final java.lang.String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
@@ -31476,6 +31787,7 @@
field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3
field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4
field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL";
+ field public static final java.lang.String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED";
field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER";
field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
@@ -31584,6 +31896,7 @@
public static final class VoicemailContract.Status implements android.provider.BaseColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static void setQuota(android.content.Context, android.telecom.PhoneAccountHandle, int, int);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -31600,6 +31913,9 @@
field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
+ field public static final java.lang.String QUOTA_OCCUPIED = "quota_occupied";
+ field public static final java.lang.String QUOTA_TOTAL = "quota_total";
+ field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -31616,6 +31932,7 @@
field public static final java.lang.String HAS_CONTENT = "has_content";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
+ field public static final java.lang.String LAST_MODIFIED = "last_modified";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String NUMBER = "number";
field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
@@ -32807,6 +33124,7 @@
public class NetworkSecurityPolicy {
method public static android.security.NetworkSecurityPolicy getInstance();
method public boolean isCleartextTrafficPermitted();
+ method public boolean isCleartextTrafficPermitted(java.lang.String);
}
}
@@ -33222,6 +33540,7 @@
field public static final int REASON_PACKAGE_BANNED = 7; // 0x7
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
field public static final int REASON_USER_STOPPED = 6; // 0x6
+ field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
public class NotificationAssistantService.Adjustment {
@@ -33251,6 +33570,7 @@
method public final void requestInterruptionFilter(int);
method public final void requestListenerHints(int);
method public final void setNotificationsShown(java.lang.String[]);
+ field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -33260,6 +33580,7 @@
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+ field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
}
public static class NotificationListenerService.Ranking {
@@ -33331,10 +33652,13 @@
method public void onClick();
method public void onStartListening();
method public void onStopListening();
- method public void onTileAdded();
+ method public int onTileAdded();
method public void onTileRemoved();
+ method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
method public final void showDialog(android.app.Dialog);
field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+ field public static final int TILE_MODE_PASSIVE = 1; // 0x1
}
}
@@ -34595,6 +34919,7 @@
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
field public static final int PROPERTY_WIFI = 8; // 0x8
+ field public static final int PROPERTY_WORK_CALL = 32; // 0x20
}
public final class CallAudioState implements android.os.Parcelable {
@@ -36307,6 +36632,7 @@
method public java.lang.Object getSystemService(java.lang.String);
method public java.lang.String getSystemServiceName(java.lang.Class<?>);
method public android.content.res.Resources.Theme getTheme();
+ method public int getUserId();
method public android.graphics.drawable.Drawable getWallpaper();
method public int getWallpaperDesiredMinimumHeight();
method public int getWallpaperDesiredMinimumWidth();
@@ -36433,7 +36759,7 @@
method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
method public int getComponentEnabledSetting(android.content.ComponentName);
method public android.graphics.drawable.Drawable getDefaultActivityIcon();
- method public java.lang.String getDefaultBrowserPackageName(int);
+ method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
method public byte[] getEphemeralCookie();
method public int getEphemeralCookieMaxSizeBytes();
@@ -36445,8 +36771,10 @@
method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
method public java.lang.String getNameForUid(int);
method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public android.content.pm.PackageInstaller getPackageInstaller();
+ method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method public java.lang.String[] getPackagesForUid(int);
method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int);
method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -36485,7 +36813,6 @@
method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
method public void setApplicationEnabledSetting(java.lang.String, int, int);
method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
- method public boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setEphemeralCookie(byte[]);
method public void setInstallerPackageName(java.lang.String, java.lang.String);
method public void verifyPendingInstall(int, int);
@@ -38875,7 +39202,7 @@
method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher);
field public static final java.util.regex.Pattern DOMAIN_NAME;
field public static final java.util.regex.Pattern EMAIL_ADDRESS;
- field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
+ field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef";
field public static final java.util.regex.Pattern IP_ADDRESS;
field public static final java.util.regex.Pattern PHONE;
field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN;
@@ -39306,7 +39633,6 @@
method public int getAction();
method public android.content.ClipData getClipData();
method public android.content.ClipDescription getClipDescription();
- method public android.view.DropPermissionHolder getDropPermissionHolder();
method public java.lang.Object getLocalState();
method public boolean getResult();
method public float getX();
@@ -39321,12 +39647,8 @@
field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
}
- public class DropPermissionHolder implements android.os.Parcelable {
- method public int describeContents();
- method public void grant();
- method public void revoke();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.DropPermissionHolder> CREATOR;
+ public final class DropPermissions {
+ method public void release();
}
public class FocusFinder {
@@ -40252,6 +40574,8 @@
field public static final int AXIS_LTRIGGER = 17; // 0x11
field public static final int AXIS_ORIENTATION = 8; // 0x8
field public static final int AXIS_PRESSURE = 2; // 0x2
+ field public static final int AXIS_RELATIVE_X = 27; // 0x1b
+ field public static final int AXIS_RELATIVE_Y = 28; // 0x1c
field public static final int AXIS_RTRIGGER = 18; // 0x12
field public static final int AXIS_RUDDER = 20; // 0x14
field public static final int AXIS_RX = 12; // 0xc
@@ -40787,6 +41111,7 @@
method public boolean hasNestedScrollingParent();
method public boolean hasOnClickListeners();
method public boolean hasOverlappingRendering();
+ method public boolean hasPointerCapture();
method public boolean hasTransientState();
method public boolean hasWindowFocus();
method public static android.view.View inflate(android.content.Context, int, android.view.ViewGroup);
@@ -40913,6 +41238,7 @@
method public void postOnAnimation(java.lang.Runnable);
method public void postOnAnimationDelayed(java.lang.Runnable, long);
method public void refreshDrawableState();
+ method public void releasePointerCapture();
method public boolean removeCallbacks(java.lang.Runnable);
method public void removeOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void removeOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
@@ -41013,6 +41339,7 @@
method public void setPaddingRelative(int, int, int, int);
method public void setPivotX(float);
method public void setPivotY(float);
+ method public void setPointerCapture();
method public void setPointerIcon(android.view.PointerIcon);
method public void setPressed(boolean);
method public final void setRight(int);
@@ -59424,8 +59751,8 @@
method public java.lang.StringBuffer appendTail(java.lang.StringBuffer);
method public int end();
method public int end(int);
- method public boolean find(int);
method public boolean find();
+ method public boolean find(int);
method public java.lang.String group();
method public java.lang.String group(int);
method public int groupCount();
@@ -59453,8 +59780,8 @@
}
public final class Pattern implements java.io.Serializable {
- method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public static java.util.regex.Pattern compile(java.lang.String);
+ method public static java.util.regex.Pattern compile(java.lang.String, int) throws java.util.regex.PatternSyntaxException;
method public int flags();
method public java.util.regex.Matcher matcher(java.lang.CharSequence);
method public static boolean matches(java.lang.String, java.lang.CharSequence);
@@ -59469,6 +59796,7 @@
field public static final int LITERAL = 16; // 0x10
field public static final int MULTILINE = 8; // 0x8
field public static final int UNICODE_CASE = 64; // 0x40
+ field public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
field public static final int UNIX_LINES = 1; // 0x1
}
diff --git a/api/test-removed.txt b/api/test-removed.txt
index f12e61e..6b7961e 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -199,6 +199,15 @@
}
+package android.test.mock {
+
+ public class MockPackageManager extends android.content.pm.PackageManager {
+ method public deprecated java.lang.String getDefaultBrowserPackageName(int);
+ method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
+ }
+
+}
+
package android.text.format {
public class DateFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4f7a109..6302d74 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -159,6 +159,7 @@
" am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
" am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
" am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
" am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
" am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
@@ -299,7 +300,11 @@
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+ "\n" +
+ "am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " and supplying temporary different task bounds indicated by\n" +
+ " <TASK_LEFT,TOP,RIGHT,BOTTOM>\n" +
"\n" +
"am stack size-docked-stack-test: test command for sizing docked stack by\n" +
" <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
@@ -1683,6 +1688,9 @@
case "resize":
runStackResize();
break;
+ case "resize-docked-stack":
+ runStackResizeDocked();
+ break;
case "positiontask":
runStackPositionTask();
break;
@@ -1751,6 +1759,20 @@
resizeStack(stackId, bounds, 0);
}
+ private void runStackResizeDocked() throws Exception {
+ final Rect bounds = getBounds();
+ final Rect taskBounds = getBounds();
+ if (bounds == null || taskBounds == null) {
+ System.err.println("Error: invalid input bounds");
+ return;
+ }
+ try {
+ mAm.resizeDockedStack(bounds, taskBounds, null, null, null);
+ } catch (RemoteException e) {
+ showError("Error: resizing docked stack " + e);
+ }
+ }
+
private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
if (bounds == null) {
showError("Error: invalid input bounds");
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ad1b3b5..24449d4 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -376,6 +376,7 @@
!= PackageInstaller.STATUS_SUCCESS) {
return 1;
}
+ System.out.println("Success");
return 0;
} finally {
try {
@@ -591,7 +592,6 @@
} else {
System.err.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
- System.err.println("Failure details: " + result.getExtras());
}
return status;
} finally {
diff --git a/core/java/android/annotation/AppIdInt.java b/core/java/android/annotation/AppIdInt.java
new file mode 100644
index 0000000..29838dd
--- /dev/null
+++ b/core/java/android/annotation/AppIdInt.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element is a multi-user application ID. This is
+ * <em>not</em> the same as a UID.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface AppIdInt {
+}
diff --git a/core/java/android/annotation/UserIdInt.java b/core/java/android/annotation/UserIdInt.java
new file mode 100644
index 0000000..7b9ce25
--- /dev/null
+++ b/core/java/android/annotation/UserIdInt.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Denotes that the annotated element is a multi-user user ID. This is
+ * <em>not</em> the same as a UID.
+ *
+ * @hide
+ */
+@Retention(SOURCE)
+@Target({METHOD, PARAMETER, FIELD})
+public @interface UserIdInt {
+}
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 72f8c77..6fc0d74 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -31,9 +31,11 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
+import android.view.View.OnFocusChangeListener;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewHierarchyEncoder;
+import android.view.ViewParent;
import android.view.Window;
import android.widget.SpinnerAdapter;
import java.lang.annotation.Retention;
@@ -1071,6 +1073,66 @@
}
/**
+ * Attempts to move focus to the ActionBar if it does not already contain the focus.
+ *
+ * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+ * @hide
+ */
+ public boolean requestFocus() {
+ return false;
+ }
+
+ /** @hide */
+ public void onDestroy() {
+ }
+
+ /**
+ * Common implementation for requestFocus that takes in the Toolbar and moves focus
+ * to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
+ * in the ActionBar and then prevents it again once it leaves.
+ *
+ * @param viewGroup The toolbar ViewGroup
+ * @return {@code true} if focus changes or {@code false} if focus doesn't change.
+ * @hide
+ */
+ protected boolean requestFocus(ViewGroup viewGroup) {
+ if (viewGroup != null && !viewGroup.hasFocus()) {
+ final ViewGroup toolbar = viewGroup.getTouchscreenBlocksFocus() ? viewGroup : null;
+ ViewParent parent = viewGroup.getParent();
+ ViewGroup container = null;
+ while (parent != null && parent instanceof ViewGroup) {
+ final ViewGroup vgParent = (ViewGroup) parent;
+ if (vgParent.getTouchscreenBlocksFocus()) {
+ container = vgParent;
+ break;
+ }
+ parent = vgParent.getParent();
+ }
+ if (container != null) {
+ container.setTouchscreenBlocksFocus(false);
+ }
+ if (toolbar != null) {
+ toolbar.setTouchscreenBlocksFocus(false);
+ }
+ viewGroup.requestFocus();
+ final View focused = viewGroup.findFocus();
+ if (focused != null) {
+ focused.setOnFocusChangeListener(new FollowOutOfActionBar(viewGroup,
+ container, toolbar));
+ } else {
+ if (container != null) {
+ container.setTouchscreenBlocksFocus(true);
+ }
+ if (toolbar != null) {
+ toolbar.setTouchscreenBlocksFocus(true);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Listener interface for ActionBar navigation events.
*
* @deprecated Action bar navigation modes are deprecated and not supported by inline
@@ -1388,4 +1450,43 @@
encoder.addProperty("gravity", gravity);
}
}
+
+ /**
+ * Tracks the focused View until it leaves the ActionBar, then it resets the
+ * touchscreenBlocksFocus value.
+ */
+ private static class FollowOutOfActionBar implements OnFocusChangeListener, Runnable {
+ private final ViewGroup mFocusRoot;
+ private final ViewGroup mContainer;
+ private final ViewGroup mToolbar;
+
+ public FollowOutOfActionBar(ViewGroup focusRoot, ViewGroup container, ViewGroup toolbar) {
+ mContainer = container;
+ mToolbar = toolbar;
+ mFocusRoot = focusRoot;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (!hasFocus) {
+ v.setOnFocusChangeListener(null);
+ final View focused = mFocusRoot.findFocus();
+ if (focused != null) {
+ focused.setOnFocusChangeListener(this);
+ } else {
+ mFocusRoot.post(this);
+ }
+ }
+ }
+
+ @Override
+ public void run() {
+ if (mContainer != null) {
+ mContainer.setTouchscreenBlocksFocus(true);
+ }
+ if (mToolbar != null) {
+ mToolbar.setTouchscreenBlocksFocus(true);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 93c6bef..8346161 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,8 @@
import android.transition.TransitionManager;
import android.util.ArrayMap;
import android.util.SuperNotCalledException;
+import android.view.DragEvent;
+import android.view.DropPermissions;
import android.view.Window.WindowControllerCallback;
import android.widget.Toolbar;
@@ -816,6 +818,7 @@
SharedElementCallback mExitTransitionListener = SharedElementCallback.NULL_CALLBACK;
private boolean mHasCurrentPermissionsRequest;
+ private boolean mEatKeyUpEvent;
/** Return the intent that started this activity. */
public Intent getIntent() {
@@ -1700,6 +1703,10 @@
mSearchManager.stopSearch();
}
+ if (mActionBar != null) {
+ mActionBar.onDestroy();
+ }
+
getApplication().dispatchActivityDestroyed(this);
}
@@ -1733,9 +1740,13 @@
*
* @param multiWindowMode True if the activity is in multi-window mode.
*/
+ @CallSuper
public void onMultiWindowModeChanged(boolean multiWindowMode) {
if (DEBUG_LIFECYCLE) Slog.v(TAG,
"onMultiWindowModeChanged " + this + ": " + multiWindowMode);
+ if (mWindow != null) {
+ mWindow.onMultiWindowModeChanged();
+ }
}
/**
@@ -1778,6 +1789,17 @@
}
/**
+ * Puts the activity in picture-in-picture mode.
+ * @see android.R.attr#supportsPictureInPicture
+ */
+ public void enterPictureInPictureMode() {
+ try {
+ ActivityManagerNative.getDefault().enterPictureInPictureMode(mToken);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
* Called by the system when the device configuration changes while your
* activity is running. Note that this will <em>only</em> be called if
* you have selected configurations you would like to handle with the
@@ -2190,14 +2212,22 @@
* @param toolbar Toolbar to set as the Activity's action bar
*/
public void setActionBar(@Nullable Toolbar toolbar) {
- if (getActionBar() instanceof WindowDecorActionBar) {
+ final ActionBar ab = getActionBar();
+ if (ab instanceof WindowDecorActionBar) {
throw new IllegalStateException("This Activity already has an action bar supplied " +
"by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
"android:windowActionBar to false in your theme to use a Toolbar instead.");
}
- // Clear out the MenuInflater to make sure that it is valid for the new Action Bar
+
+ // If we reach here then we're setting a new action bar
+ // First clear out the MenuInflater to make sure that it is valid for the new Action Bar
mMenuInflater = null;
+ // If we have an action bar currently, destroy it
+ if (ab != null) {
+ ab.onDestroy();
+ }
+
ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
mActionBar = tbab;
mWindow.setCallback(tbab.getWrappedWindowCallback());
@@ -2812,9 +2842,25 @@
// Let action bars open menus in response to the menu key prioritized over
// the window handling it
- if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&
+ final int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ // Capture the Alt-up and send focus to the ActionBar
+ final int action = event.getAction();
+ if (action == KeyEvent.ACTION_DOWN) {
+ if (event.hasModifiers(KeyEvent.META_ALT_ON)) {
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null && actionBar.isShowing() && actionBar.requestFocus()) {
+ mEatKeyUpEvent = true;
+ return true;
+ }
+ }
+ } else if (action == KeyEvent.ACTION_UP && mEatKeyUpEvent) {
+ mEatKeyUpEvent = false;
+ return true;
+ }
}
Window win = getWindow();
@@ -5285,8 +5331,7 @@
*/
public boolean isTaskRoot() {
try {
- return ActivityManagerNative.getDefault()
- .getTaskForActivity(mToken, true) >= 0;
+ return ActivityManagerNative.getDefault().getTaskForActivity(mToken, true) >= 0;
} catch (RemoteException e) {
return false;
}
@@ -6007,6 +6052,22 @@
}
/**
+ * Enable or disable virtual reality (VR) mode.
+ *
+ * <p>VR mode is a hint to Android system services to switch to modes optimized for
+ * high-performance stereoscopic rendering.</p>
+ *
+ * @param enabled {@code true} to enable this mode.
+ */
+ public void setVrMode(boolean enabled) {
+ try {
+ ActivityManagerNative.getDefault().setVrMode(mToken, enabled);
+ } catch (RemoteException e) {
+ // pass
+ }
+ }
+
+ /**
* Start an action mode of the default type {@link ActionMode#TYPE_PRIMARY}.
*
* @param callback Callback that will manage lifecycle events for this action mode
@@ -6289,6 +6350,21 @@
mActivityTransitionState.startPostponedEnterTransition();
}
+ /**
+ * Create {@link DropPermissions} object bound to this activity and controlling the access
+ * permissions for content URIs associated with the {@link DragEvent}.
+ * @param event Drag event
+ * @return The DropPermissions object used to control access to the content URIs. Null if
+ * no content URIs are associated with the event or if permissions could not be granted.
+ */
+ public DropPermissions requestDropPermissions(DragEvent event) {
+ DropPermissions dropPermissions = DropPermissions.obtain(event);
+ if (dropPermissions != null && dropPermissions.take(getActivityToken())) {
+ return dropPermissions;
+ }
+ return null;
+ }
+
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 81fe23c..8637dde 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -485,12 +485,9 @@
return stackId == FREEFORM_WORKSPACE_STACK_ID;
}
- /**
- * Returns true if the task bounds should persist across power cycles.
- */
+ /** Returns true if the task bounds should persist across power cycles. */
public static boolean persistTaskBounds(int stackId) {
- return isStaticStack(stackId) &&
- stackId != DOCKED_STACK_ID && stackId != PINNED_STACK_ID;
+ return stackId == FREEFORM_WORKSPACE_STACK_ID;
}
/**
@@ -559,14 +556,6 @@
public static boolean isAlwaysOnTop(int stackId) {
return stackId == PINNED_STACK_ID;
}
-
- /**
- * Returns true if the application windows in this stack should be displayed above all
- * other application windows, including during the animation.
- */
- public static boolean shouldIncreaseApplicationWindowLayer(int stackId) {
- return stackId == PINNED_STACK_ID || stackId == DOCKED_STACK_ID;
- }
}
/**
@@ -1248,6 +1237,18 @@
public static final int RECENT_IGNORE_HOME_STACK_TASKS = 0x0008;
/**
+ * Ignores all tasks that are on the docked stack.
+ * @hide
+ */
+ public static final int RECENT_INGORE_DOCKED_STACK_TASKS = 0x0010;
+
+ /**
+ * Ignores all tasks that are on the pinned stack.
+ * @hide
+ */
+ public static final int RECENT_INGORE_PINNED_STACK_TASKS = 0x0020;
+
+ /**
* <p></p>Return a list of the tasks that the user has recently launched, with
* the most recent being first and older ones after in order.
*
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f11bf742..da21099 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -332,10 +332,9 @@
{
data.enforceInterface(IActivityManager.descriptor);
final int taskId = data.readInt();
- final int launchStackId = data.readInt();
final Bundle options =
data.readInt() == 0 ? null : Bundle.CREATOR.createFromParcel(data);
- final int result = startActivityFromRecents(taskId, launchStackId, options);
+ final int result = startActivityFromRecents(taskId, options);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -571,6 +570,14 @@
return true;
}
+ case ACTIVITY_RELAUNCHED_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder token = data.readStrongBinder();
+ activityRelaunched(token);
+ reply.writeNoException();
+ return true;
+ }
+
case GET_CALLING_PACKAGE_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
@@ -786,6 +793,39 @@
return true;
}
+ case RESIZE_DOCKED_STACK_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final boolean hasBounds = data.readInt() != 0;
+ Rect bounds = null;
+ if (hasBounds) {
+ bounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempDockedTaskBounds = data.readInt() != 0;
+ Rect tempDockedTaskBounds = null;
+ if (hasTempDockedTaskBounds) {
+ tempDockedTaskBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempDockedTaskInsetBounds = data.readInt() != 0;
+ Rect tempDockedTaskInsetBounds = null;
+ if (hasTempDockedTaskInsetBounds) {
+ tempDockedTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempOtherTaskBounds = data.readInt() != 0;
+ Rect tempOtherTaskBounds = null;
+ if (hasTempOtherTaskBounds) {
+ tempOtherTaskBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ final boolean hasTempOtherTaskInsetBounds = data.readInt() != 0;
+ Rect tempOtherTaskInsetBounds = null;
+ if (hasTempOtherTaskInsetBounds) {
+ tempOtherTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+ }
+ resizeDockedStack(bounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+ tempOtherTaskBounds, tempOtherTaskInsetBounds);
+ reply.writeNoException();
+ return true;
+ }
+
case POSITION_TASK_IN_STACK_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int taskId = data.readInt();
@@ -1845,6 +1885,15 @@
return true;
}
+ case GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder activityToken = data.readStrongBinder();
+ IBinder perm = getUriPermissionOwnerForActivity(activityToken);
+ reply.writeNoException();
+ reply.writeStrongBinder(perm);
+ return true;
+ }
+
case GRANT_URI_PERMISSION_FROM_OWNER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder owner = data.readStrongBinder();
@@ -2759,6 +2808,21 @@
reply.writeInt(pipMode ? 1 : 0);
return true;
}
+ case ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final IBinder token = data.readStrongBinder();
+ enterPictureInPictureMode(token);
+ reply.writeNoException();
+ return true;
+ }
+ case SET_VR_MODE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ final IBinder token = data.readStrongBinder();
+ final boolean enable = data.readInt() == 1;
+ setVrMode(token, enable);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -3064,13 +3128,12 @@
data.recycle();
return result != 0;
}
- public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+ public int startActivityFromRecents(int taskId, Bundle options)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeInt(taskId);
- data.writeInt(launchStackId);
if (options == null) {
data.writeInt(0);
} else {
@@ -3358,6 +3421,17 @@
data.recycle();
reply.recycle();
}
+ public void activityRelaunched(IBinder token) throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(ACTIVITY_RELAUNCHED_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
public String getCallingPackage(IBinder token) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -3668,6 +3742,50 @@
reply.recycle();
}
@Override
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
+ throws RemoteException
+ {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ if (dockedBounds != null) {
+ data.writeInt(1);
+ dockedBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempDockedTaskBounds != null) {
+ data.writeInt(1);
+ tempDockedTaskBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempDockedTaskInsetBounds != null) {
+ data.writeInt(1);
+ tempDockedTaskInsetBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempOtherTaskBounds != null) {
+ data.writeInt(1);
+ tempOtherTaskBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ if (tempOtherTaskInsetBounds != null) {
+ data.writeInt(1);
+ tempOtherTaskInsetBounds.writeToParcel(data, 0);
+ } else {
+ data.writeInt(0);
+ }
+ mRemote.transact(RESIZE_DOCKED_STACK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+ @Override
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
{
Parcel data = Parcel.obtain();
@@ -5106,6 +5224,19 @@
return res;
}
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(activityToken);
+ mRemote.transact(GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION, data, reply, 0);
+ reply.readException();
+ IBinder res = reply.readStrongBinder();
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -5889,6 +6020,18 @@
return res;
}
+ public void setVrMode(IBinder token, boolean enabled) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ data.writeInt(enabled ? 1 : 0);
+ mRemote.transact(SET_VR_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
@Override
public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
Parcel data = Parcel.obtain();
@@ -6433,5 +6576,17 @@
return pipMode;
}
+ @Override
+ public void enterPictureInPictureMode(IBinder token) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(token);
+ mRemote.transact(ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cee1aa5..e596a68 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,6 +17,7 @@
package android.app;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import android.content.Context;
import android.content.Intent;
@@ -67,7 +68,8 @@
* The bounds (window size) that the activity should be launched in. Set to null explicitly for
* full screen. If the key is not found, previous bounds will be preserved.
* NOTE: This value is ignored on devices that don't have
- * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
+ * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
+ * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
* @hide
*/
public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
@@ -145,6 +147,12 @@
private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
/**
+ * The stack id the activity should be launched into.
+ * @hide
+ */
+ private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+
+ /**
* Where the docked stack should be positioned.
* @hide
*/
@@ -215,6 +223,7 @@
private int mResultCode;
private int mExitCoordinatorIndex;
private PendingIntent mUsageTimeReport;
+ private int mLaunchStackId = INVALID_STACK_ID;
private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
private AppTransitionAnimationSpec mAnimSpecs[];
@@ -754,6 +763,7 @@
mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
break;
}
+ mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
if (opts.containsKey(KEY_ANIM_SPECS)) {
Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
@@ -901,7 +911,19 @@
}
/** @hide */
- public int getDockCreateMode() { return mDockCreateMode; }
+ public int getLaunchStackId() {
+ return mLaunchStackId;
+ }
+
+ /** @hide */
+ public void setLaunchStackId(int launchStackId) {
+ mLaunchStackId = launchStackId;
+ }
+
+ /** @hide */
+ public int getDockCreateMode() {
+ return mDockCreateMode;
+ }
/** @hide */
public void setDockCreateMode(int dockCreateMode) {
@@ -1049,6 +1071,7 @@
b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
break;
}
+ b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
if (mAnimSpecs != null) {
b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3962abd..4531a74 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -101,6 +101,9 @@
import android.view.WindowManagerGlobal;
import android.renderscript.RenderScriptCacheDir;
import android.security.keystore.AndroidKeyStoreProvider;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.ErrnoException;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceInteractor;
@@ -123,6 +126,7 @@
import java.net.InetAddress;
import java.text.DateFormat;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -819,43 +823,6 @@
setCoreSettings(coreSettings);
- /*
- * Two possible indications that this package could be
- * sharing its runtime with other packages:
- *
- * 1.) the sharedUserId attribute is set in the manifest,
- * indicating a request to share a VM with other
- * packages with the same sharedUserId.
- *
- * 2.) the application element of the manifest has an
- * attribute specifying a non-default process name,
- * indicating the desire to run in another packages VM.
- *
- * If sharing is enabled we do not have a unique application
- * in a process and therefore cannot rely on the package
- * name inside the runtime.
- */
- IPackageManager pm = getPackageManager();
- android.content.pm.PackageInfo pi = null;
- try {
- pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
- } catch (RemoteException e) {
- }
- if (pi != null) {
- boolean sharedUserIdSet = (pi.sharedUserId != null);
- boolean processNameNotDefault =
- (pi.applicationInfo != null &&
- !appInfo.packageName.equals(pi.applicationInfo.processName));
- boolean sharable = (sharedUserIdSet || processNameNotDefault);
-
- // Tell the VMRuntime about the application, unless it is shared
- // inside a process.
- if (!sharable) {
- VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
- appInfo.processName);
- }
- }
-
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
@@ -4155,6 +4122,15 @@
r.pendingIntents = pendingNewIntents;
}
}
+
+ // For each relaunch request, activity manager expects an answer
+ if (!r.onlyLocalRequest && fromServer) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(token);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
break;
}
}
@@ -4269,6 +4245,13 @@
ActivityClientRecord r = mActivities.get(tmp.token);
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
if (r == null) {
+ if (!tmp.onlyLocalRequest) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
+ } catch (RemoteException e) {
+ // If the system process has died, it's game over for everyone.
+ }
+ }
return;
}
@@ -4314,6 +4297,14 @@
r.overrideConfig = tmp.overrideConfig;
handleLaunchActivity(r, currentIntent);
+
+ if (!tmp.onlyLocalRequest) {
+ try {
+ ActivityManagerNative.getDefault().activityRelaunched(r.token);
+ } catch (RemoteException e) {
+ // If the system process has died, it's game over for everyone.
+ }
+ }
}
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
@@ -4667,6 +4658,87 @@
}
}
+ private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
+ final ApplicationInfo appInfo = loadedApk.getApplicationInfo();
+ if (isSharingRuntime(appInfo)) {
+ // If sharing is enabled we do not have a unique application
+ // in a process and therefore cannot rely on the package
+ // name inside the runtime.
+ return;
+ }
+ final List<String> codePaths = new ArrayList<>();
+ if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) {
+ codePaths.add(appInfo.sourceDir);
+ }
+ if (appInfo.splitSourceDirs != null) {
+ Collections.addAll(codePaths, appInfo.splitSourceDirs);
+ }
+
+ if (codePaths.isEmpty()) {
+ // If there are no code paths there's no need to setup a profile file and register with
+ // the runtime,
+ return;
+ }
+
+ // Add an extension to the file name to better reveal its intended use.
+ // Keep in sync with BackgroundDexOptService.
+ final String profileExtension = ".prof";
+ final File profileFile = new File(cacheDir, loadedApk.mPackageName + profileExtension);
+ if (!profileFile.exists()) {
+ FileDescriptor fd = null;
+ try {
+ final int permissions = 0600; // read-write for user.
+ fd = Os.open(profileFile.getAbsolutePath(), OsConstants.O_CREAT, permissions);
+ Os.fchmod(fd, permissions);
+ Os.fchown(fd, appInfo.uid, appInfo.uid);
+ } catch (ErrnoException e) {
+ Log.w(TAG, "Unable to create jit profile file " + profileFile, e);
+ try {
+ Os.unlink(profileFile.getAbsolutePath());
+ } catch (ErrnoException unlinkErr) {
+ Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr);
+ }
+ return;
+ } finally {
+ IoUtils.closeQuietly(fd);
+ }
+ }
+
+ VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir,
+ codePaths.toArray(new String[codePaths.size()]));
+ }
+
+ /*
+ * Two possible indications that this package could be
+ * sharing its runtime with other packages:
+ *
+ * 1) the sharedUserId attribute is set in the manifest,
+ * indicating a request to share a VM with other
+ * packages with the same sharedUserId.
+ *
+ * 2) the application element of the manifest has an
+ * attribute specifying a non-default process name,
+ * indicating the desire to run in another packages VM.
+ */
+ private static boolean isSharingRuntime(ApplicationInfo appInfo) {
+ IPackageManager pm = getPackageManager();
+ android.content.pm.PackageInfo pi = null;
+ try {
+ pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ }
+ if (pi != null) {
+ boolean sharedUserIdSet = (pi.sharedUserId != null);
+ boolean processNameNotDefault = (pi.applicationInfo != null) &&
+ !appInfo.packageName.equals(pi.applicationInfo.processName);
+ boolean sharable = sharedUserIdSet || processNameNotDefault;
+ return sharable;
+ }
+ // We couldn't get information for the package. Be pessimistic and assume
+ // it's sharing the runtime.
+ return true;
+ }
+
private void updateDefaultDensity() {
if (mCurDefaultDisplayDpi != Configuration.DENSITY_DPI_UNDEFINED
&& mCurDefaultDisplayDpi != DisplayMetrics.DENSITY_DEVICE
@@ -4870,12 +4942,14 @@
+ "due to missing cache directory");
}
- // Use codeCacheDir to store generated/compiled graphics code
+ // Use codeCacheDir to store generated/compiled graphics code and jit profiling data.
final File codeCacheDir = appContext.getCodeCacheDir();
if (codeCacheDir != null) {
setupGraphicsSupport(data.info, codeCacheDir);
+ setupJitProfileSupport(data.info, codeCacheDir);
} else {
- Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
+ Log.e(TAG, "Unable to setupGraphicsSupport and setupJitProfileSupport " +
+ "due to missing code-cache directory");
}
}
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index ddb2d46..7d0d1b4 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -27,7 +27,7 @@
return gApplicationLoaders;
}
- public ClassLoader getClassLoader(String zip, String librarySearchPath,
+ public ClassLoader getClassLoader(String zip, boolean isBundled, String librarySearchPath,
String libraryPermittedPath, ClassLoader parent)
{
/*
@@ -56,7 +56,8 @@
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
PathClassLoader pathClassloader =
- new PathClassLoader(zip, librarySearchPath, libraryPermittedPath, parent);
+ new PathClassLoader(zip, isBundled, librarySearchPath,
+ libraryPermittedPath, parent);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
mLoaders.put(zip, pathClassloader);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 460e68c..42b18384 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,7 +42,6 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -214,10 +213,15 @@
}
@Override
- public int[] getPackageGids(String packageName)
+ public int[] getPackageGids(String packageName) throws NameNotFoundException {
+ return getPackageGids(packageName, 0);
+ }
+
+ @Override
+ public int[] getPackageGids(String packageName, int flags)
throws NameNotFoundException {
try {
- int[] gids = mPM.getPackageGids(packageName, mContext.getUserId());
+ int[] gids = mPM.getPackageGidsEtc(packageName, flags, mContext.getUserId());
if (gids != null) {
return gids;
}
@@ -229,10 +233,20 @@
}
@Override
- public int getPackageUid(String packageName, int userHandle)
+ public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+ return getPackageUidAsUser(packageName, flags, mContext.getUserId());
+ }
+
+ @Override
+ public int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException {
+ return getPackageUidAsUser(packageName, 0, userId);
+ }
+
+ @Override
+ public int getPackageUidAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
try {
- int uid = mPM.getPackageUid(packageName, userHandle);
+ int uid = mPM.getPackageUidEtc(packageName, flags, userId);
if (uid >= 0) {
return uid;
}
@@ -591,12 +605,12 @@
@SuppressWarnings("unchecked")
@Override
public List<PackageInfo> getInstalledPackages(int flags) {
- return getInstalledPackages(flags, mContext.getUserId());
+ return getInstalledPackagesAsUser(flags, mContext.getUserId());
}
/** @hide */
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
try {
ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
return slice.getList();
@@ -780,7 +794,7 @@
* @hide
*/
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
try {
return mPM.queryIntentReceivers(
intent,
@@ -794,7 +808,7 @@
@Override
public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
- return queryBroadcastReceivers(intent, flags, mContext.getUserId());
+ return queryBroadcastReceiversAsUser(intent, flags, mContext.getUserId());
}
@Override
@@ -1421,7 +1435,7 @@
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
final VerificationParams verificationParams = new VerificationParams(null, null,
- null, VerificationParams.NO_UID, null);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, null, mContext.getUserId());
}
@@ -1429,9 +1443,9 @@
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
- null, VerificationParams.NO_UID, manifestDigest);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
}
@@ -1455,7 +1469,7 @@
public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
String installerPackageName, int userId) {
final VerificationParams verificationParams = new VerificationParams(null, null,
- null, VerificationParams.NO_UID, null);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
userId);
}
@@ -1463,10 +1477,10 @@
@Override
public void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams) {
final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
- null, VerificationParams.NO_UID, manifestDigest);
+ null, VerificationParams.NO_UID);
installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
encryptionParams, mContext.getUserId());
}
@@ -1547,7 +1561,7 @@
}
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
try {
return mPM.getIntentVerificationStatus(packageName, userId);
} catch (RemoteException e) {
@@ -1557,7 +1571,7 @@
}
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
try {
return mPM.updateIntentVerificationStatus(packageName, status, userId);
} catch (RemoteException e) {
@@ -1587,7 +1601,7 @@
}
@Override
- public String getDefaultBrowserPackageName(int userId) {
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
try {
return mPM.getDefaultBrowserPackageName(userId);
} catch (RemoteException e) {
@@ -1597,7 +1611,7 @@
}
@Override
- public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
try {
return mPM.setDefaultBrowserPackageName(packageName, userId);
} catch (RemoteException e) {
@@ -1858,7 +1872,17 @@
}
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ try {
+ return mPM.setPackageSuspendedAsUser(packageName, suspended, userId);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return false;
+ }
+
+ @Override
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
try {
mPM.getPackageSizeInfo(packageName, userHandle, observer);
@@ -1905,7 +1929,7 @@
}
@Override
- public void addPreferredActivity(IntentFilter filter, int match,
+ public void addPreferredActivityAsUser(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
try {
mPM.addPreferredActivity(filter, match, set, activity, userId);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 984a186..a147cc8 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -719,7 +719,7 @@
Fragment f = op.fragment;
int containerId = f.mContainerId;
if (mManager.mAdded != null) {
- for (int i = 0; i < mManager.mAdded.size(); i++) {
+ for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
Fragment old = mManager.mAdded.get(i);
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG,
diff --git a/core/java/android/app/DatePickerDialog.java b/core/java/android/app/DatePickerDialog.java
index 3fbbdff..8d7f347 100644
--- a/core/java/android/app/DatePickerDialog.java
+++ b/core/java/android/app/DatePickerDialog.java
@@ -16,6 +16,9 @@
package android.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -35,95 +38,126 @@
/**
* A simple dialog containing an {@link android.widget.DatePicker}.
- *
- * <p>See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
- * guide.</p>
+ * <p>
+ * See the <a href="{@docRoot}guide/topics/ui/controls/pickers.html">Pickers</a>
+ * guide.
*/
public class DatePickerDialog extends AlertDialog implements OnClickListener,
OnDateChangedListener {
-
private static final String YEAR = "year";
private static final String MONTH = "month";
private static final String DAY = "day";
private final DatePicker mDatePicker;
- private final OnDateSetListener mDateSetListener;
private final Calendar mCalendar;
+ private OnDateSetListener mDateSetListener;
+
private boolean mTitleNeedsUpdate = true;
/**
- * The callback used to indicate the user is done filling in the date.
+ * Creates a new date picker dialog for the current date using the parent
+ * context's default date picker dialog theme.
+ *
+ * @param context the parent context
*/
- public interface OnDateSetListener {
-
- /**
- * @param view The view associated with this listener.
- * @param year The year that was set.
- * @param monthOfYear The month that was set (0-11) for compatibility
- * with {@link java.util.Calendar}.
- * @param dayOfMonth The day of the month that was set.
- */
- void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth);
+ public DatePickerDialog(Context context) {
+ this(context, 0);
}
/**
- * @param context The context the dialog is to run in.
- * @param callBack How the parent is notified that the date is set.
- * @param year The initial year of the dialog.
- * @param monthOfYear The initial month of the dialog.
- * @param dayOfMonth The initial day of the dialog.
+ * Creates a new date picker dialog for the current date.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
*/
- public DatePickerDialog(Context context,
- OnDateSetListener callBack,
- int year,
- int monthOfYear,
- int dayOfMonth) {
- this(context, 0, callBack, year, monthOfYear, dayOfMonth);
- }
-
- static int resolveDialogTheme(Context context, int resid) {
- if (resid == 0) {
- final TypedValue outValue = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
- return outValue.resourceId;
- } else {
- return resid;
- }
- }
-
- /**
- * @param context The context the dialog is to run in.
- * @param theme the theme to apply to this dialog
- * @param listener How the parent is notified that the date is set.
- * @param year The initial year of the dialog.
- * @param monthOfYear The initial month of the dialog.
- * @param dayOfMonth The initial day of the dialog.
- */
- public DatePickerDialog(Context context, int theme, OnDateSetListener listener, int year,
- int monthOfYear, int dayOfMonth) {
- super(context, resolveDialogTheme(context, theme));
-
- mDateSetListener = listener;
- mCalendar = Calendar.getInstance();
+ public DatePickerDialog(Context context, @StyleRes int themeResId) {
+ super(context, resolveDialogTheme(context, themeResId));
final Context themeContext = getContext();
final LayoutInflater inflater = LayoutInflater.from(themeContext);
final View view = inflater.inflate(R.layout.date_picker_dialog, null);
setView(view);
+
setButton(BUTTON_POSITIVE, themeContext.getString(R.string.ok), this);
setButton(BUTTON_NEGATIVE, themeContext.getString(R.string.cancel), this);
setButtonPanelLayoutHint(LAYOUT_HINT_SIDE);
+ mCalendar = Calendar.getInstance();
+
+ final int year = mCalendar.get(Calendar.YEAR);
+ final int monthOfYear = mCalendar.get(Calendar.MONTH);
+ final int dayOfMonth = mCalendar.get(Calendar.DAY_OF_MONTH);
mDatePicker = (DatePicker) view.findViewById(R.id.datePicker);
mDatePicker.init(year, monthOfYear, dayOfMonth, this);
mDatePicker.setValidationCallback(mValidationCallback);
}
+ /**
+ * Creates a new date picker dialog for the specified date using the parent
+ * context's default date picker dialog theme.
+ *
+ * @param context the parent context
+ * @param listener the listener to call when the user sets the date
+ * @param year the initially selected year
+ * @param month the initially selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the initially selected day of month (1-31, depending
+ * on month)
+ */
+ public DatePickerDialog(@Nullable Context context, @Nullable OnDateSetListener listener,
+ int year, int month, int dayOfMonth) {
+ this(context, 0, listener, year, month, dayOfMonth);
+ }
+
+ /**
+ * Creates a new date picker dialog for the specified date.
+ *
+ * @param context the parent context
+ * @param themeResId the resource ID of the theme against which to inflate
+ * this dialog, or {@code 0} to use the parent
+ * {@code context}'s default alert dialog theme
+ * @param listener the listener to call when the user sets the date
+ * @param year the initially selected year
+ * @param month the initially selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the initially selected day of month (1-31, depending
+ * on month)
+ */
+ public DatePickerDialog(@NonNull Context context, @StyleRes int themeResId,
+ @Nullable OnDateSetListener listener, int year, int month, int dayOfMonth) {
+ this(context, themeResId);
+
+ mDateSetListener = listener;
+
+ mDatePicker.updateDate(year, month, dayOfMonth);
+ }
+
+ static int resolveDialogTheme(@NonNull Context context, @StyleRes int themeResId) {
+ if (themeResId == 0) {
+ final TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.datePickerDialogTheme, outValue, true);
+ return outValue.resourceId;
+ } else {
+ return themeResId;
+ }
+ }
+
@Override
- public void onDateChanged(DatePicker view, int year, int month, int day) {
- mDatePicker.init(year, month, day, this);
- updateTitle(year, month, day);
+ public void onDateChanged(DatePicker view, int year, int month, int dayOfMonth) {
+ mDatePicker.init(year, month, dayOfMonth, this);
+ updateTitle(year, month, dayOfMonth);
+ }
+
+ /**
+ * Sets the listener to call when the user sets the date.
+ *
+ * @param listener the listener to call when the user sets the date
+ */
+ public void setOnDateSetListener(@Nullable OnDateSetListener listener) {
+ mDateSetListener = listener;
}
@Override
@@ -145,10 +179,11 @@
}
/**
- * Gets the {@link DatePicker} contained in this dialog.
+ * Returns the {@link DatePicker} contained in this dialog.
*
- * @return The calendar view.
+ * @return the date picker
*/
+ @NonNull
public DatePicker getDatePicker() {
return mDatePicker;
}
@@ -156,20 +191,22 @@
/**
* Sets the current date.
*
- * @param year The date year.
- * @param monthOfYear The date month.
- * @param dayOfMonth The date day of month.
+ * @param year the year
+ * @param month the month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth the day of month (1-31, depending on month)
*/
- public void updateDate(int year, int monthOfYear, int dayOfMonth) {
- mDatePicker.updateDate(year, monthOfYear, dayOfMonth);
+ public void updateDate(int year, int month, int dayOfMonth) {
+ mDatePicker.updateDate(year, month, dayOfMonth);
}
- private void updateTitle(int year, int month, int day) {
+ private void updateTitle(int year, int month, int dayOfMonth) {
if (!mDatePicker.getCalendarViewShown()) {
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, month);
- mCalendar.set(Calendar.DAY_OF_MONTH, day);
- String title = DateUtils.formatDateTime(mContext,
+ mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+
+ final String title = DateUtils.formatDateTime(mContext,
mCalendar.getTimeInMillis(),
DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_WEEKDAY
@@ -177,12 +214,12 @@
| DateUtils.FORMAT_ABBREV_MONTH
| DateUtils.FORMAT_ABBREV_WEEKDAY);
setTitle(title);
+
mTitleNeedsUpdate = true;
- } else {
- if (mTitleNeedsUpdate) {
- mTitleNeedsUpdate = false;
- setTitle(R.string.date_picker_dialog_title);
- }
+ } else if (mTitleNeedsUpdate) {
+ setTitle(R.string.date_picker_dialog_title);
+
+ mTitleNeedsUpdate = false;
}
}
@@ -213,4 +250,19 @@
}
}
};
+
+ /**
+ * The listener used to indicate the user has finished selecting a date.
+ */
+ public interface OnDateSetListener {
+ /**
+ * @param view the picker associated with the dialog
+ * @param year the selected year
+ * @param month the selected month (0-11 for compatibility with
+ * {@link Calendar#MONTH})
+ * @param dayOfMonth th selected day of the month (1-31, depending on
+ * month)
+ */
+ void onDateSet(DatePicker view, int year, int month, int dayOfMonth);
+ }
}
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index fb0e79b..ed4bb28 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -27,6 +27,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
import android.net.Uri;
+import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.Downloads;
@@ -105,8 +106,17 @@
public final static String COLUMN_LOCAL_URI = "local_uri";
/**
- * The pathname of the file where the download is stored.
+ * Path to the downloaded file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly access
+ * this path. Instead of trying to open this path directly, apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access.
+ *
+ * @deprecated apps should transition to using
+ * {@link ContentResolver#openFileDescriptor(Uri, String)}
+ * instead.
*/
+ @Deprecated
public final static String COLUMN_LOCAL_FILENAME = "local_filename";
/**
@@ -908,16 +918,22 @@
}
}
- private ContentResolver mResolver;
- private String mPackageName;
+ private final ContentResolver mResolver;
+ private final String mPackageName;
+
private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
+ private boolean mAccessFilename;
/**
* @hide
*/
- public DownloadManager(ContentResolver resolver, String packageName) {
- mResolver = resolver;
- mPackageName = packageName;
+ public DownloadManager(Context context) {
+ mResolver = context.getContentResolver();
+ mPackageName = context.getPackageName();
+
+ // Callers can access filename columns when targeting old platform
+ // versions; otherwise we throw telling them it's deprecated.
+ mAccessFilename = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N;
}
/**
@@ -933,6 +949,11 @@
}
}
+ /** {@hide} */
+ public void setAccessFilename(boolean accessFilename) {
+ mAccessFilename = accessFilename;
+ }
+
/**
* Enqueue a new download. The download will start automatically once the download manager is
* ready to execute it and connectivity is available.
@@ -997,7 +1018,7 @@
if (underlyingCursor == null) {
return null;
}
- return new CursorTranslator(underlyingCursor, mBaseUri);
+ return new CursorTranslator(underlyingCursor, mBaseUri, mAccessFilename);
}
/**
@@ -1265,11 +1286,13 @@
* underlying data.
*/
private static class CursorTranslator extends CursorWrapper {
- private Uri mBaseUri;
+ private final Uri mBaseUri;
+ private final boolean mAccessFilename;
- public CursorTranslator(Cursor cursor, Uri baseUri) {
+ public CursorTranslator(Cursor cursor, Uri baseUri, boolean accessFilename) {
super(cursor);
mBaseUri = baseUri;
+ mAccessFilename = accessFilename;
}
@Override
@@ -1290,8 +1313,19 @@
@Override
public String getString(int columnIndex) {
- return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() :
- super.getString(columnIndex);
+ final String columnName = getColumnName(columnIndex);
+ switch (columnName) {
+ case COLUMN_LOCAL_URI:
+ return getLocalUri();
+ case COLUMN_LOCAL_FILENAME:
+ if (!mAccessFilename) {
+ throw new IllegalArgumentException(
+ "COLUMN_LOCAL_FILENAME is deprecated;"
+ + " use ContentResolver.openFileDescriptor() instead");
+ }
+ default:
+ return super.getString(columnIndex);
+ }
}
private String getLocalUri() {
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index 20f3495..c6cc452 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -31,6 +31,7 @@
import android.view.ViewGroupOverlay;
import android.view.ViewTreeObserver;
import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
import java.util.ArrayList;
@@ -500,6 +501,10 @@
@Override
protected void onTransitionsComplete() {
moveSharedElementsFromOverlay();
+ final ViewGroup decorView = getDecor();
+ if (decorView != null) {
+ decorView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ }
}
private void sharedElementTransitionStarted() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 64c69af..ceb14ad 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -92,7 +92,7 @@
int userId) throws RemoteException;
public boolean startNextMatchingActivity(IBinder callingActivity,
Intent intent, Bundle options) throws RemoteException;
- public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+ public int startActivityFromRecents(int taskId, Bundle options)
throws RemoteException;
public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
throws RemoteException;
@@ -122,6 +122,7 @@
PersistableBundle persistentState, CharSequence description) throws RemoteException;
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
+ public void activityRelaunched(IBinder token) throws RemoteException;
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
throws RemoteException;
@@ -145,7 +146,31 @@
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) throws RemoteException;
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
- public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
+ public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
+ throws RemoteException;
+
+ /**
+ * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
+ *
+ * @param dockedBounds The bounds for the docked stack.
+ * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
+ * might be different from the stack bounds to allow more
+ * flexibility while resizing, or {@code null} if they should be the
+ * same as the stack bounds.
+ * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
+ * When resizing, we usually "freeze" the layout of a task. To
+ * achieve that, we also need to "freeze" the insets, which
+ * gets achieved by changing task bounds but not bounds used
+ * to calculate the insets in this transient state
+ * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
+ * {@code null} if they should be the same as the stack bounds.
+ * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
+ * stacks.
+ * @throws RemoteException
+ */
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
public List<StackInfo> getAllStackInfos() throws RemoteException;
public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -363,6 +388,7 @@
public String getProviderMimeType(Uri uri, int userId) throws RemoteException;
public IBinder newUriPermissionOwner(String name) throws RemoteException;
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;
public void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg,
Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;
public void revokeUriPermissionFromOwner(IBinder owner, Uri uri,
@@ -550,6 +576,10 @@
public boolean inPictureInPictureMode(IBinder token) throws RemoteException;
+ public void enterPictureInPictureMode(IBinder token) throws RemoteException;
+
+ public void setVrMode(IBinder token, boolean enabled) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -914,4 +944,9 @@
int IN_MULTI_WINDOW_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 352;
int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
+ int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
+ int ACTIVITY_RELAUNCHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+ int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
+ int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358;
+ int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 136b810..e60cb03 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -54,6 +54,8 @@
int getTopicPriority(String pkg, int uid, in Notification.Topic topic);
void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance);
int getTopicImportance(String pkg, int uid, in Notification.Topic topic);
+ void setAppImportance(String pkg, int uid, int importance);
+ boolean doesAppUseTopics(String pkg, int uid);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
@@ -76,6 +78,8 @@
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
+ void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
boolean isSystemConditionProviderEnabled(String path);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 4b0935c..560e22a 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -18,5 +18,9 @@
/** @hide */
oneway interface ITaskStackListener {
+ /** Called whenever there are changes to the state of tasks in a stack. */
void onTaskStackChanged();
+
+ /** Called whenever an Activity is moved to the pinned stack from another stack. */
+ void onActivityPinned();
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 23e4d97..3910657 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -21,11 +21,14 @@
import android.app.trust.ITrustManager;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.RemoteException;
import android.os.IBinder;
+import android.os.IUserManager;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.view.IWindowManager;
import android.view.IOnKeyguardExitResult;
import android.view.WindowManagerGlobal;
@@ -40,6 +43,7 @@
public class KeyguardManager {
private IWindowManager mWM;
private ITrustManager mTrustManager;
+ private IUserManager mUserManager;
/**
* Intent used to prompt user for device credentials.
@@ -49,6 +53,13 @@
"android.app.action.CONFIRM_DEVICE_CREDENTIAL";
/**
+ * Intent used to prompt user for device credentials.
+ * @hide
+ */
+ public static final String ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER =
+ "android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER";
+
+ /**
* A CharSequence dialog title to show to the user when used with a
* {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
* @hide
@@ -71,7 +82,7 @@
* @return the intent for launching the activity or null if no password is required.
**/
public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
- if (!isKeyguardSecure()) return null;
+ if (!isDeviceSecure()) return null;
Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
intent.putExtra(EXTRA_TITLE, title);
intent.putExtra(EXTRA_DESCRIPTION, description);
@@ -81,6 +92,28 @@
}
/**
+ * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
+ * for the given user. The caller is expected to launch this activity using
+ * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+ * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
+ *
+ * @return the intent for launching the activity or null if no password is required.
+ *
+ * @hide
+ */
+ public Intent createConfirmDeviceCredentialIntent(
+ CharSequence title, CharSequence description, int userId) {
+ if (!isDeviceSecure(userId)) return null;
+ Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
+ intent.putExtra(EXTRA_TITLE, title);
+ intent.putExtra(EXTRA_DESCRIPTION, description);
+ intent.putExtra(Intent.EXTRA_USER_ID, userId);
+ // For security reasons, only allow this to come from system settings.
+ intent.setPackage("com.android.settings");
+ return intent;
+ }
+
+ /**
* @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
* and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
* instead; this allows you to seamlessly hide the keyguard as your application
@@ -162,6 +195,8 @@
mWM = WindowManagerGlobal.getWindowManagerService();
mTrustManager = ITrustManager.Stub.asInterface(
ServiceManager.getService(Context.TRUST_SERVICE));
+ mUserManager = IUserManager.Stub.asInterface(
+ ServiceManager.getService(Context.USER_SERVICE));
}
/**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 7313fd1..855b21e 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -366,12 +366,21 @@
}
}
+ String libraryPermittedPath = mAppDir + File.pathSeparator + mDataDir;
+ boolean isBundledApp = false;
+
if (mApplicationInfo.isSystemApp()) {
+ isBundledApp = true;
// Add path to system libraries to libPaths;
// Access to system libs should be limited
// to bundled applications; this is why updated
// system apps are not included.
libPaths.add(System.getProperty("java.library.path"));
+
+ // This is necessary to grant bundled apps access to
+ // libraries located in subdirectories of /system/lib
+ libraryPermittedPath += File.pathSeparator +
+ System.getProperty("java.library.path");
}
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
@@ -389,10 +398,8 @@
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- String libraryPermittedPath = mAppDir + File.pathSeparator + mDataDir;
-
- mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, librarySearchPath,
- libraryPermittedPath, mBaseClassLoader);
+ mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, isBundledApp,
+ librarySearchPath, libraryPermittedPath, mBaseClassLoader);
StrictMode.setThreadPolicy(oldPolicy);
} else {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 620ab50..a392abd 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -145,6 +145,11 @@
private static final int MAX_CHARSEQUENCE_LENGTH = 5 * 1024;
/**
+ * Maximum entries of reply text that are accepted by Builder and friends.
+ */
+ private static final int MAX_REPLY_HISTORY = 5;
+
+ /**
* A timestamp related to this notification, in milliseconds since the epoch.
*
* Default value: {@link System#currentTimeMillis() Now}.
@@ -745,6 +750,12 @@
public static final String EXTRA_SUB_TEXT = "android.subText";
/**
+ * {@link #extras} key: this is the remote input history, as supplied to
+ * {@link Builder#setRemoteInputHistory(CharSequence[])}.
+ */
+ public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
+
+ /**
* {@link #extras} key: this is a small piece of additional text as supplied to
* {@link Builder#setContentInfo(CharSequence)}.
*/
@@ -2324,6 +2335,34 @@
}
/**
+ * Set the remote input history.
+ *
+ * This should be set to the most recent inputs that have been sent
+ * through a {@link RemoteInput} of this Notification and cleared once the it is no
+ * longer relevant (e.g. for chat notifications once the other party has responded).
+ *
+ * The most recent input must be stored at the 0 index, the second most recent at the
+ * 1 index, etc. Note that the system will limit both how far back the inputs will be shown
+ * and how much of each individual input is shown.
+ *
+ * <p>Note: The reply text will only be shown on notifications that have least one action
+ * with a {@code RemoteInput}.</p>
+ */
+ public Builder setRemoteInputHistory(CharSequence[] text) {
+ if (text == null) {
+ mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, null);
+ } else {
+ final int N = Math.min(MAX_REPLY_HISTORY, text.length);
+ CharSequence[] safe = new CharSequence[N];
+ for (int i = 0; i < N; i++) {
+ safe[i] = safeCharSequence(text[i]);
+ }
+ mN.extras.putCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY, safe);
+ }
+ return this;
+ }
+
+ /**
* Set the large number at the right-hand side of the notification. This is
* equivalent to setContentInfo, although it might show the number in a different
* font size for readability.
@@ -3001,6 +3040,7 @@
resetNotificationHeader(contentView);
resetContentMargins(contentView);
contentView.setViewVisibility(R.id.right_icon, View.GONE);
+ contentView.setViewVisibility(R.id.title, View.GONE);
contentView.setTextViewText(R.id.title, null);
contentView.setTextViewText(R.id.text, null);
contentView.setViewVisibility(R.id.line3, View.GONE);
@@ -3047,6 +3087,7 @@
bindNotificationHeader(contentView);
bindLargeIcon(contentView);
if (ex.getCharSequence(EXTRA_TITLE) != null) {
+ contentView.setViewVisibility(R.id.title, View.VISIBLE);
contentView.setTextViewText(R.id.title,
processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
}
@@ -3065,10 +3106,26 @@
}
// Note getStandardView may hide line 3 again.
contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
+ setContentMinHeight(contentView, showProgress || mN.mLargeIcon != null);
return contentView;
}
+ /**
+ * @param remoteView the remote view to update the minheight in
+ * @param hasMinHeight does it have a mimHeight
+ * @hide
+ */
+ void setContentMinHeight(RemoteViews remoteView, boolean hasMinHeight) {
+ int minHeight = 0;
+ if (hasMinHeight) {
+ // we need to set the minHeight of the notification
+ minHeight = mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_min_content_height);
+ }
+ remoteView.setInt(R.id.notification_main_column, "setMinimumHeight", minHeight);
+ }
+
private boolean handleProgressBar(boolean hasProgress, RemoteViews contentView, Bundle ex) {
final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
final int progress = ex.getInt(EXTRA_PROGRESS, 0);
@@ -3214,6 +3271,14 @@
private void resetStandardTemplateWithActions(RemoteViews big) {
big.setViewVisibility(R.id.actions, View.GONE);
big.removeAllViews(R.id.actions);
+
+ big.setViewVisibility(R.id.notification_material_reply_container, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_1, null);
+
+ big.setViewVisibility(R.id.notification_material_reply_text_2, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_2, null);
+ big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
+ big.setTextViewText(R.id.notification_material_reply_text_3, null);
}
private RemoteViews applyStandardTemplateWithActions(int layoutId) {
@@ -3221,18 +3286,62 @@
resetStandardTemplateWithActions(big);
+ boolean validRemoteInput = false;
+
int N = mActions.size();
if (N > 0) {
big.setViewVisibility(R.id.actions, View.VISIBLE);
if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
for (int i=0; i<N; i++) {
- final RemoteViews button = generateActionButton(mActions.get(i));
+ Action action = mActions.get(i);
+ validRemoteInput |= hasValidRemoteInput(action);
+
+ final RemoteViews button = generateActionButton(action);
big.addView(R.id.actions, button);
}
}
+
+ CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
+ if (validRemoteInput && replyText != null
+ && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
+ big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
+
+ if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
+ big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_2, replyText[1]);
+
+ if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
+ big.setViewVisibility(
+ R.id.notification_material_reply_text_3, View.VISIBLE);
+ big.setTextViewText(R.id.notification_material_reply_text_3, replyText[2]);
+ }
+ }
+ }
+
return big;
}
+ private boolean hasValidRemoteInput(Action action) {
+ if (TextUtils.isEmpty(action.title) || action.actionIntent == null) {
+ // Weird actions
+ return false;
+ }
+
+ RemoteInput[] remoteInputs = action.getRemoteInputs();
+ if (remoteInputs == null) {
+ return false;
+ }
+
+ for (RemoteInput r : remoteInputs) {
+ CharSequence[] choices = r.getChoices();
+ if (r.getAllowFreeFormInput() || (choices != null && choices.length != 0)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Construct a RemoteViews for the final 1U notification layout. In order:
* 1. Custom contentView from the caller
@@ -3312,6 +3421,37 @@
return applyStandardTemplateWithActions(getBigBaseLayoutResource());
}
+ /**
+ * Construct a RemoteViews for the display in public contexts like on the lockscreen.
+ *
+ * @hide
+ */
+ public RemoteViews makePublicContentView() {
+ if (mN.publicVersion != null) {
+ final Builder builder = recoverBuilder(mContext, mN.publicVersion);
+ return builder.makeContentView();
+ }
+ Bundle savedBundle = mN.extras;
+ Style style = mStyle;
+ mStyle = null;
+ Icon largeIcon = mN.mLargeIcon;
+ mN.mLargeIcon = null;
+ Bundle publicExtras = new Bundle();
+ publicExtras.putBoolean(EXTRA_SHOW_WHEN,
+ savedBundle.getBoolean(EXTRA_SHOW_WHEN));
+ publicExtras.putBoolean(EXTRA_SHOW_CHRONOMETER,
+ savedBundle.getBoolean(EXTRA_SHOW_CHRONOMETER));
+ publicExtras.putCharSequence(EXTRA_TITLE,
+ mContext.getString(R.string.notification_hidden_text));
+ mN.extras = publicExtras;
+ final RemoteViews publicView = applyStandardTemplate(getBaseLayoutResource());
+ mN.extras = savedBundle;
+ mN.mLargeIcon = largeIcon;
+ mStyle = style;
+ return publicView;
+ }
+
+
private RemoteViews generateActionButton(Action action) {
final boolean tombstone = (action.actionIntent == null);
@@ -3801,12 +3941,7 @@
contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(mSummaryText));
contentView.setViewVisibility(R.id.line3, View.VISIBLE);
}
- int imageMinHeight = mBuilder.mContext.getResources().getDimensionPixelSize(
- R.dimen.notification_big_picture_content_min_height_with_picture);
- // We need to make space for the right image, so we're enforcing a minheight if there
- // is a picture.
- int minHeight = (mBuilder.mN.mLargeIcon == null) ? 0 : imageMinHeight;
- contentView.setInt(R.id.notification_main_column, "setMinimumHeight", minHeight);
+ mBuilder.setContentMinHeight(contentView, mBuilder.mN.mLargeIcon != null);
if (mBigLargeIconSet) {
mBuilder.mN.mLargeIcon = oldLargeIcon;
@@ -3873,8 +4008,7 @@
public static class BigTextStyle extends Style {
private static final int MAX_LINES = 13;
- private static final int LINES_CONSUMED_BY_ACTIONS = 3;
- private static final int LINES_CONSUMED_BY_SUMMARY = 2;
+ private static final int LINES_CONSUMED_BY_ACTIONS = 4;
private CharSequence mBigText;
@@ -3944,8 +4078,10 @@
mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
- contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
- contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
+ CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
+ contentView.setTextViewText(R.id.big_text, bigTextText);
+ contentView.setViewVisibility(R.id.big_text,
+ TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines());
mBuilder.addProfileBadge(contentView, R.id.profile_badge_large_template);
@@ -3958,14 +4094,9 @@
private int calculateMaxLines() {
int lineCount = MAX_LINES;
boolean hasActions = mBuilder.mActions.size() > 0;
- boolean hasSummary = (mSummaryTextSet ? mSummaryText
- : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT)) != null;
if (hasActions) {
lineCount -= LINES_CONSUMED_BY_ACTIONS;
}
- if (hasSummary) {
- lineCount -= LINES_CONSUMED_BY_SUMMARY;
- }
return lineCount;
}
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 85d9831..9a3c820 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -637,10 +637,12 @@
public static final int SUPPRESSED_EFFECTS_UNSET = -1;
public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0;
public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1;
+ public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 2;
private static final int[] ALL_SUPPRESSED_EFFECTS = {
SUPPRESSED_EFFECT_LIGHTS,
SUPPRESSED_EFFECT_PEEK,
+ SUPPRESSED_EFFECT_SCREEN_ON,
};
/**
@@ -750,6 +752,7 @@
switch (effect) {
case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS";
case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK";
+ case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
default: return "UNKNOWN_" + effect;
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 288a2cb..89d52f2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -247,7 +247,7 @@
new CachedServiceFetcher<DownloadManager>() {
@Override
public DownloadManager createService(ContextImpl ctx) {
- return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+ return new DownloadManager(ctx);
}});
registerService(Context.BATTERY_SERVICE, BatteryManager.class,
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index f7848f9..8475840 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -22,6 +22,7 @@
import android.accessibilityservice.IAccessibilityServiceClient;
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.annotation.NonNull;
+import android.annotation.TestApi;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -856,6 +857,7 @@
*
* @hide
*/
+ @TestApi
public boolean grantRuntimePermission(String packageName, String permission,
UserHandle userHandle) {
synchronized (mLock) {
@@ -884,6 +886,7 @@
*
* @hide
*/
+ @TestApi
public boolean revokeRuntimePermission(String packageName, String permission,
UserHandle userHandle) {
synchronized (mLock) {
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 22e79b6..5b5bba4 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -52,6 +52,8 @@
import android.util.Log;
import android.view.WindowManagerGlobal;
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -309,11 +311,7 @@
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode file", e);
} finally {
- try {
- fd.close();
- } catch (IOException e) {
- // Ignore
- }
+ IoUtils.closeQuietly(fd);
}
}
} catch (RemoteException e) {
@@ -321,7 +319,7 @@
}
return null;
}
-
+
private Bitmap getDefaultWallpaperLocked(Context context) {
InputStream is = openDefaultWallpaper(context);
if (is != null) {
@@ -331,11 +329,7 @@
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode stream", e);
} finally {
- try {
- is.close();
- } catch (IOException e) {
- // Ignore
- }
+ IoUtils.closeQuietly(is);
}
}
return null;
@@ -738,30 +732,65 @@
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
setWallpaper(resources.openRawResource(resid), fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
}
} catch (RemoteException e) {
// Ignore
}
}
-
+
/**
* Change the current system wallpaper to a bitmap. The given bitmap is
* converted to a PNG and stored as the wallpaper. On success, the intent
* {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
*
+ * <p>This method is equivalent to calling
+ * {@link #setBitmap(Bitmap, Rect, boolean)} and passing {@code null} for the
+ * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
+ * parameter.
+ *
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
* @param bitmap The bitmap to save.
*
- * @throws IOException If an error occurs reverting to the built-in
- * wallpaper.
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * to the provided image.
*/
public void setBitmap(Bitmap bitmap) throws IOException {
+ setBitmap(bitmap, null, true);
+ }
+
+ /**
+ * Change the current system wallpaper to a bitmap, specifying a hint about
+ * which subrectangle of the full image is to be visible. The OS will then
+ * try to best present the given portion of the full image as the static system
+ * wallpaper image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * <p>Passing {@code null} as the {@code visibleHint} parameter is equivalent to
+ * passing (0, 0, {@code fullImage.getWidth()}, {@code fullImage.getHeight()}).
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
+ *
+ * @param fullImage A bitmap that will supply the wallpaper imagery.
+ * @param visibleCropHint The rectangular subregion of {@code fullImage} that should be
+ * displayed as wallpaper. Passing {@code null} for this parameter means that
+ * the full image should be displayed if possible given the image's and device's
+ * aspect ratios, etc.
+ * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+ * image for restore to a future device; {@code false} otherwise.
+ *
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * to the provided image.
+ * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
+ * empty or invalid.
+ */
+ public void setBitmap(Bitmap fullImage, Rect visibleCropHint, boolean allowBackup)
+ throws IOException {
+ validateRect(visibleCropHint);
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
@@ -775,17 +804,21 @@
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
+ fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
} catch (RemoteException e) {
// Ignore
}
}
+ private final void validateRect(Rect rect) {
+ if (rect != null && rect.isEmpty()) {
+ throw new IllegalArgumentException("visibleCrop rectangle must be valid and non-empty");
+ }
+ }
+
/**
* Change the current system wallpaper to a specific byte stream. The
* give InputStream is copied into persistent storage and will now be
@@ -793,15 +826,60 @@
* image. On success, the intent {@link Intent#ACTION_WALLPAPER_CHANGED}
* is broadcast.
*
+ * <p>This method is equivalent to calling
+ * {@link #setStream(InputStream, Rect, boolean)} and passing {@code null} for the
+ * {@code visibleCrop} rectangle and {@code true} for the {@code allowBackup}
+ * parameter.
+ *
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#SET_WALLPAPER}.
*
- * @param data A stream containing the raw data to install as a wallpaper.
+ * @param bitmapData A stream containing the raw data to install as a wallpaper.
*
- * @throws IOException If an error occurs reverting to the built-in
- * wallpaper.
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * based on the provided image data.
*/
- public void setStream(InputStream data) throws IOException {
+ public void setStream(InputStream bitmapData) throws IOException {
+ setStream(bitmapData, null, true);
+ }
+
+ private void setWallpaper(InputStream data, FileOutputStream fos)
+ throws IOException {
+ byte[] buffer = new byte[32768];
+ int amt;
+ while ((amt=data.read(buffer)) > 0) {
+ fos.write(buffer, 0, amt);
+ }
+ }
+
+ /**
+ * Change the current system wallpaper to a specific byte stream, specifying a
+ * hint about which subrectangle of the full image is to be visible. The OS will
+ * then try to best present the given portion of the full image as the static system
+ * wallpaper image. The data from the given InputStream is copied into persistent
+ * storage and will then be used as the system wallpaper. Currently the data must
+ * be either a JPEG or PNG image. On success, the intent
+ * {@link Intent#ACTION_WALLPAPER_CHANGED} is broadcast.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#SET_WALLPAPER}.
+ *
+ * @param bitmapData A stream containing the raw data to install as a wallpaper.
+ * @param visibleCropHint The rectangular subregion of the streamed image that should be
+ * displayed as wallpaper. Passing {@code null} for this parameter means that
+ * the full image should be displayed if possible given the image's and device's
+ * aspect ratios, etc.
+ * @param allowBackup {@code true} if the OS is permitted to back up this wallpaper
+ * image for restore to a future device; {@code false} otherwise.
+ *
+ * @throws IOException If an error occurs when attempting to set the wallpaper
+ * based on the provided image data.
+ * @throws IllegalArgumentException If the {@code visibleCropHint} rectangle is
+ * empty or invalid.
+ */
+ public void setStream(InputStream bitmapData, Rect visibleCropHint, boolean allowBackup)
+ throws IOException {
+ validateRect(visibleCropHint);
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
return;
@@ -815,26 +893,15 @@
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
- setWallpaper(data, fos);
+ setWallpaper(bitmapData, fos);
} finally {
- if (fos != null) {
- fos.close();
- }
+ IoUtils.closeQuietly(fos);
}
} catch (RemoteException e) {
// Ignore
}
}
- private void setWallpaper(InputStream data, FileOutputStream fos)
- throws IOException {
- byte[] buffer = new byte[32768];
- int amt;
- while ((amt=data.read(buffer)) > 0) {
- fos.write(buffer, 0, amt);
- }
- }
-
/**
* Return whether any users are currently set to use the wallpaper
* with the given resource ID. That is, their wallpaper has been
@@ -915,8 +982,8 @@
* the size of their workspace.
*
* <p>Note developers, who don't seem to be reading this. This is
- * for <em>home screens</em> to tell what size wallpaper they would like.
- * Nobody else should be calling this! Certainly not other non-home-screen
+ * for <em>home apps</em> to tell what size wallpaper they would like.
+ * Nobody else should be calling this! Certainly not other non-home
* apps that change the wallpaper. Those apps are supposed to
* <b>retrieve</b> the suggested size so they can construct a wallpaper
* that matches it.
@@ -1053,11 +1120,11 @@
}
/**
- * Set the position of the current wallpaper within any larger space, when
+ * Set the display position of the current wallpaper within any larger space, when
* that wallpaper is visible behind the given window. The X and Y offsets
* are floating point numbers ranging from 0 to 1, representing where the
* wallpaper should be positioned within the screen space. These only
- * make sense when the wallpaper is larger than the screen.
+ * make sense when the wallpaper is larger than the display.
*
* @param windowToken The window who these offsets should be associated
* with, as returned by {@link android.view.View#getWindowToken()
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 08b7d62..08e9b1e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -40,8 +40,8 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.provider.ContactsContract.Directory;
+import android.provider.Settings;
import android.security.Credentials;
import android.service.restrictions.RestrictionsReceiver;
import android.util.Log;
@@ -56,14 +56,14 @@
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
-import java.security.NoSuchAlgorithmException;
+import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -88,13 +88,15 @@
private final Context mContext;
private final IDevicePolicyManager mService;
+ private boolean mParentInstance;
private static final String REMOTE_EXCEPTION_MESSAGE =
"Failed to talk with device policy manager service";
- private DevicePolicyManager(Context context) {
+ private DevicePolicyManager(Context context, boolean parentInstance) {
this(context, IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)));
+ mParentInstance = parentInstance;
}
/** @hide */
@@ -106,7 +108,7 @@
/** @hide */
public static DevicePolicyManager create(Context context) {
- DevicePolicyManager me = new DevicePolicyManager(context);
+ DevicePolicyManager me = new DevicePolicyManager(context, false);
return me.mService != null ? me : null;
}
@@ -1031,7 +1033,7 @@
public void setPasswordQuality(@NonNull ComponentName admin, int quality) {
if (mService != null) {
try {
- mService.setPasswordQuality(admin, quality);
+ mService.setPasswordQuality(admin, quality, mParentInstance);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -1052,7 +1054,7 @@
public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) {
if (mService != null) {
try {
- return mService.getPasswordQuality(admin, userHandle);
+ return mService.getPasswordQuality(admin, userHandle, mParentInstance);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -1622,7 +1624,7 @@
public boolean isActivePasswordSufficient() {
if (mService != null) {
try {
- return mService.isActivePasswordSufficient(myUserId());
+ return mService.isActivePasswordSufficient(myUserId(), mParentInstance);
} catch (RemoteException e) {
Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
}
@@ -1791,6 +1793,9 @@
* not acceptable for the current constraints or if the user has not been decrypted yet.
*/
public boolean resetPassword(String password, int flags) {
+ if (mParentInstance) {
+ throw new SecurityException("Reset password does not work across profiles.");
+ }
if (mService != null) {
try {
return mService.resetPassword(password, flags);
@@ -3060,6 +3065,8 @@
*
* <p>If the device owner information is {@code null} or empty then the device owner info is
* cleared and the user owner info is shown on the lock screen if it is set.
+ * <p>If the device owner information contains only whitespaces then the message on the lock
+ * screen will be blank and the user will not be allowed to change it.
*
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user
@@ -3092,6 +3099,48 @@
}
/**
+ * Called by device or profile owners for setting the package suspended for this user.
+ * A suspended package will not be started by the package manager, its notifications will
+ * be hidden and it will not show up in recents. The package must already be installed.
+ *
+ * @param admin The name of the admin component to check.
+ * @param packageName The package name of the app to suspend or unsuspend.
+ * @param suspended If set to {@code true} than the package will be suspended, if set to
+ * {@code false} the package will be unsuspended.
+ * @return boolean {@code true} if the operation was successfully performed, {@code false}
+ * otherwise.
+ */
+ public boolean setPackageSuspended(@NonNull ComponentName admin, String packageName,
+ boolean suspended) {
+ if (mService != null) {
+ try {
+ return mService.setPackageSuspended(admin, packageName, suspended);
+ } catch (RemoteException re) {
+ Log.w(TAG, "Failed talking with device policy service", re);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Called by device or profile owners to determine if a package is suspended.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The name of the package to retrieve the suspended status of.
+ * @return boolean {@code true} if the package is suspended, {@code false} otherwise.
+ */
+ public boolean getPackageSuspended(@NonNull ComponentName admin, String packageName) {
+ if (mService != null) {
+ try {
+ return mService.getPackageSuspended(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Sets the enabled state of the profile. A profile should be enabled only once it is ready to
* be used. Only the profile owner can call this.
*
@@ -3270,8 +3319,69 @@
}
/**
- * Called by a profile or device owner to set the application restrictions for a given target
- * application running in the profile.
+ * Called by a profile owner or device owner to grant permission to a package to manage
+ * application restrictions for the calling user via {@link #setApplicationRestrictions} and
+ * {@link #getApplicationRestrictions}.
+ * <p>
+ * This permission is persistent until it is later cleared by calling this method with a
+ * {@code null} value or uninstalling the managing package.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The package name which will be given access to application restrictions
+ * APIs. If {@code null} is given the current package will be cleared.
+ */
+ public void setApplicationRestrictionsManagingPackage(@NonNull ComponentName admin,
+ @Nullable String packageName) {
+ if (mService != null) {
+ try {
+ mService.setApplicationRestrictionsManagingPackage(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile owner or device owner to retrieve the application restrictions managing
+ * package for the current user, or {@code null} if none is set.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The package name allowed to manage application restrictions on the current user, or
+ * {@code null} if none is set.
+ */
+ public String getApplicationRestrictionsManagingPackage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getApplicationRestrictionsManagingPackage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if the calling package has been granted permission via
+ * {@link #setApplicationRestrictionsManagingPackage} to manage application
+ * restrictions for the calling user.
+ */
+ public boolean isCallerApplicationRestrictionsManagingPackage() {
+ if (mService != null) {
+ try {
+ return mService.isCallerApplicationRestrictionsManagingPackage();
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sets the application restrictions for a given target application running in the calling user.
+ *
+ * <p>The caller must be a profile or device owner on that user, or the package allowed to
+ * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage};
+ * otherwise a security exception will be thrown.
*
* <p>The provided {@link Bundle} consists of key-value pairs, where the types of values may be:
* <ul>
@@ -3281,24 +3391,25 @@
* <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]}
* </ul>
*
- * <p>The application restrictions are only made visible to the target application and the
- * profile or device owner.
- *
* <p>If the restrictions are not available yet, but may be applied in the near future,
- * the admin can notify the target application of that by adding
+ * the caller can notify the target application of that by adding
* {@link UserManager#KEY_RESTRICTIONS_PENDING} to the settings parameter.
*
- * <p>The calling device admin must be a profile or device owner; if it is not, a security
- * exception will be thrown.
+ * <p>The application restrictions are only made visible to the target application via
+ * {@link UserManager#getApplicationRestrictions(String)}, in addition to the profile or
+ * device owner, and the application restrictions managing package via
+ * {@link #getApplicationRestrictions}.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if called by the application restrictions managing package.
* @param packageName The name of the package to update restricted settings for.
* @param settings A {@link Bundle} to be parsed by the receiving application, conveying a new
* set of active restrictions.
*
+ * @see #setApplicationRestrictionsManagingPackage
* @see UserManager#KEY_RESTRICTIONS_PENDING
*/
- public void setApplicationRestrictions(@NonNull ComponentName admin, String packageName,
+ public void setApplicationRestrictions(@Nullable ComponentName admin, String packageName,
Bundle settings) {
if (mService != null) {
try {
@@ -3854,19 +3965,23 @@
}
/**
- * Called by a profile or device owner to get the application restrictions for a given target
- * application running in the profile.
+ * Retrieves the application restrictions for a given target application running in the calling
+ * user.
*
- * <p>The calling device admin must be a profile or device owner; if it is not, a security
- * exception will be thrown.
+ * <p>The caller must be a profile or device owner on that user, or the package allowed to
+ * manage application restrictions via {@link #setApplicationRestrictionsManagingPackage};
+ * otherwise a security exception will be thrown.
*
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
+ * {@code null} if called by the application restrictions managing package.
* @param packageName The name of the package to fetch restricted settings of.
* @return {@link Bundle} of settings corresponding to what was set last time
* {@link DevicePolicyManager#setApplicationRestrictions} was called, or an empty {@link Bundle}
* if no restrictions have been set.
+ *
+ * @see {@link #setApplicationRestrictionsManagingPackage}
*/
- public Bundle getApplicationRestrictions(@NonNull ComponentName admin, String packageName) {
+ public Bundle getApplicationRestrictions(@Nullable ComponentName admin, String packageName) {
if (mService != null) {
try {
return mService.getApplicationRestrictions(admin, packageName);
@@ -4034,6 +4149,10 @@
* <p>When account management is disabled for an account type, adding or removing an account
* of that type will not be possible.
*
+ * <p>From {@link android.os.Build.VERSION_CODES#N} the profile or device owner can still use
+ * {@link android.accounts.AccountManager} APIs to add or remove accounts when account
+ * management for a specific type is disabled.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param accountType For which account management is disabled or enabled.
* @param disabled The boolean indicating that account management will be disabled (true) or
@@ -4679,4 +4798,159 @@
return null;
}
}
+
+ /**
+ * Called by device owner to reboot the device.
+ */
+ public void reboot(@NonNull ComponentName admin) {
+ try {
+ mService.reboot(admin);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ }
+ }
+
+ /**
+ * Called by a device admin to set the short support message. This will
+ * be displayed to the user in settings screens where funtionality has
+ * been disabled by the admin.
+ *
+ * The message should be limited to a short statement such as
+ * "This setting is disabled by your administrator. Contact someone@example.com
+ * for support."
+ * If the message is longer than 200 characters it may be truncated.
+ *
+ * @see #setLongSupportMessage
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param message Short message to be displayed to the user in settings or null to
+ * clear the existing message.
+ */
+ public void setShortSupportMessage(@NonNull ComponentName admin,
+ @Nullable String message) {
+ if (mService != null) {
+ try {
+ mService.setShortSupportMessage(admin, message);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Called by a device admin to get the short support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ * or null if no message has been set.
+ */
+ public String getShortSupportMessage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getShortSupportMessage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called by a device admin to set the long support message. This will
+ * be displayed to the user in the device administators settings screen.
+ *
+ * @see #setShortSupportMessage
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param message Long message to be displayed to the user in settings or null to
+ * clear the existing message.
+ */
+ public void setLongSupportMessage(@NonNull ComponentName admin,
+ @Nullable String message) {
+ if (mService != null) {
+ try {
+ mService.setLongSupportMessage(admin, message);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ }
+
+ /**
+ * Called by a device admin to get the long support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ * or null if no message has been set.
+ */
+ public String getLongSupportMessage(@NonNull ComponentName admin) {
+ if (mService != null) {
+ try {
+ return mService.getLongSupportMessage(admin);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Called by the system to get the short support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle user id the admin is running as.
+ * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+ *
+ * @hide
+ */
+ public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.getShortSupportMessageForUser(admin, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Called by the system to get the long support message.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param userHandle user id the admin is running as.
+ * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+ *
+ * @hide
+ */
+ public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+ if (mService != null) {
+ try {
+ return mService.getLongSupportMessageForUser(admin, userHandle);
+ } catch (RemoteException e) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Obtains a {@link DevicePolicyManager} whose calls act on the parent profile.
+ *
+ * <p> Note only some methods will work on the parent Manager.
+ *
+ * @return a new instance of {@link DevicePolicyManager} that acts on the parent profile.
+ */
+ public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) {
+ try {
+ if (!mService.isManagedProfile(admin)) {
+ throw new SecurityException("The current user does not have a parent profile.");
+ }
+ return new DevicePolicyManager(mContext, true);
+ } catch (RemoteException re) {
+ Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+ return null;
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 1708ee3..754cb43 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -35,8 +35,8 @@
* {@hide}
*/
interface IDevicePolicyManager {
- void setPasswordQuality(in ComponentName who, int quality);
- int getPasswordQuality(in ComponentName who, int userHandle);
+ void setPasswordQuality(in ComponentName who, int quality, boolean parent);
+ int getPasswordQuality(in ComponentName who, int userHandle, boolean parent);
void setPasswordMinimumLength(in ComponentName who, int length);
int getPasswordMinimumLength(in ComponentName who, int userHandle);
@@ -67,7 +67,7 @@
long getPasswordExpiration(in ComponentName who, int userHandle);
- boolean isActivePasswordSufficient(int userHandle);
+ boolean isActivePasswordSufficient(int userHandle, boolean parent);
int getCurrentFailedPasswordAttempts(int userHandle);
int getProfileWithMinimumFailedPasswordsForWipe(int userHandle);
@@ -130,6 +130,9 @@
boolean setDeviceOwnerLockScreenInfo(in ComponentName who, String deviceOwnerInfo);
String getDeviceOwnerLockScreenInfo();
+ boolean setPackageSuspended(in ComponentName admin, String packageName, boolean suspended);
+ boolean getPackageSuspended(in ComponentName admin, String packageName);
+
boolean installCaCert(in ComponentName admin, in byte[] certBuffer);
void uninstallCaCerts(in ComponentName admin, in String[] aliases);
void enforceCanManageCaCerts(in ComponentName admin);
@@ -146,6 +149,9 @@
void setApplicationRestrictions(in ComponentName who, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String packageName);
+ void setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName);
+ String getApplicationRestrictionsManagingPackage(in ComponentName admin);
+ boolean isCallerApplicationRestrictionsManagingPackage();
void setRestrictionsProvider(in ComponentName who, in ComponentName provider);
ComponentName getRestrictionsProvider(int userHandle);
@@ -238,4 +244,13 @@
boolean isManagedProfile(in ComponentName admin);
boolean isSystemOnlyUser(in ComponentName admin);
String getWifiMacAddress();
+ void reboot(in ComponentName admin);
+
+ void setShortSupportMessage(in ComponentName admin, in String message);
+ String getShortSupportMessage(in ComponentName admin);
+ void setLongSupportMessage(in ComponentName admin, in String message);
+ String getLongSupportMessage(in ComponentName admin);
+
+ String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+ String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
}
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 2886cda..0fce7a9 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -21,6 +21,7 @@
import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
+import android.os.Build;
import android.os.RemoteException;
import android.util.Log;
@@ -29,10 +30,9 @@
* discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
* <p />
* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and
- * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except
- * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user
- * as the client. In addition tethering usage, usage by removed users and apps, and usage by system
- * is also included in the results.
+ * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain
+ * data about themselves. See the below note for special cases in which apps can obtain data about
+ * other applications.
* <h3>
* Summary queries
* </h3>
@@ -51,13 +51,20 @@
* multiple buckets for a particular key but all Bucket's state is going to be
* {@link NetworkStats.Bucket#STATE_ALL}.
* <p />
- * <b>NOTE:</b> This API requires the permission
+ * <b>NOTE:</b> Accessing stats for apps other than the calling app requires the permission
* {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and
* will not be granted to third-party apps. However, declaring the permission implies intention to
* use the API and the user of the device can grant permission through the Settings application.
* Profile owner apps are automatically granted permission to query data on the profile they manage
- * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get
- * access to usage data of the primary user.
+ * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier-
+ * privileged apps likewise get access to usage data for all users on the device.
+ * <p />
+ * In addition to tethering usage, usage by removed users and apps, and usage by the system
+ * is also included in the results for callers with one of these higher levels of access.
+ * <p />
+ * <b>NOTE:</b> Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required
+ * the above permission, even to access an app's own data usage, and carrier-privileged apps were
+ * not included.
*/
public class NetworkStatsManager {
private final static String TAG = "NetworkStatsManager";
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 1fb7825..002f63f 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.UUID;
+
/**
* This class represents a single call, its state and properties.
* It implements {@link Parcelable} for inter-process message passing.
@@ -67,14 +69,21 @@
private String mNumber;
private boolean mMultiParty;
private final boolean mOutgoing;
+ private final UUID mUUID;
/**
* Creates BluetoothHeadsetClientCall instance.
*/
public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
boolean multiParty, boolean outgoing) {
+ this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing);
+ }
+
+ public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state,
+ String number, boolean multiParty, boolean outgoing) {
mDevice = device;
mId = id;
+ mUUID = uuid;
mState = state;
mNumber = number != null ? number : "";
mMultiParty = multiParty;
@@ -134,6 +143,16 @@
}
/**
+ * Gets call's UUID.
+ *
+ * @return call uuid
+ * @hide
+ */
+ public UUID getUUID() {
+ return mUUID;
+ }
+
+ /**
* Gets call's current state.
*
* @return state of this particular phone call.
@@ -180,6 +199,8 @@
builder.append(loggable ? mDevice.hashCode() : mDevice);
builder.append(", mId: ");
builder.append(mId);
+ builder.append(", mUUID: ");
+ builder.append(mUUID);
builder.append(", mState: ");
switch (mState) {
case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
@@ -210,8 +231,8 @@
@Override
public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
- in.readInt(), in.readInt(), in.readString(),
- in.readInt() == 1, in.readInt() == 1);
+ in.readInt(), UUID.fromString(in.readString()), in.readInt(),
+ in.readString(), in.readInt() == 1, in.readInt() == 1);
}
@Override
@@ -224,6 +245,7 @@
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(mDevice, 0);
out.writeInt(mId);
+ out.writeString(mUUID.toString());
out.writeInt(mState);
out.writeString(mNumber);
out.writeInt(mMultiParty ? 1 : 0);
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index c934e8d..0b80f8a 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -36,6 +36,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
+import java.util.List;
/**
* Representation of a clipped data on the clipboard.
@@ -914,6 +915,27 @@
}
}
+ /** @hide */
+ public void collectUris(List<Uri> out) {
+ for (int i = 0; i < mItems.size(); ++i) {
+ ClipData.Item item = getItemAt(i);
+
+ if (item.getUri() != null) {
+ out.add(item.getUri());
+ }
+
+ Intent intent = item.getIntent();
+ if (intent != null) {
+ if (intent.getData() != null) {
+ out.add(intent.getData());
+ }
+ if (intent.getClipData() != null) {
+ intent.getClipData().collectUris(out);
+ }
+ }
+ }
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index d12595f..16b5a4b 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.AssetFileDescriptor;
+import android.database.CrossProcessCursorWrapper;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -32,27 +33,34 @@
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.FileNotFoundException;
import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
- * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
- * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
- * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
- * no longer needed and can be killed to free up resources.
- *
- * <p>Note that you should generally create a new ContentProviderClient instance
- * for each thread that will be performing operations. Unlike
+ * The public interface object used to interact with a specific
+ * {@link ContentProvider}.
+ * <p>
+ * Instances can be obtained by calling
+ * {@link ContentResolver#acquireContentProviderClient} or
+ * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
+ * be released using {@link #close()} in order to indicate to the system that
+ * the underlying {@link ContentProvider} is no longer needed and can be killed
+ * to free up resources.
+ * <p>
+ * Note that you should generally create a new ContentProviderClient instance
+ * for each thread that will be performing operations. Unlike
* {@link ContentResolver}, the methods here such as {@link #query} and
- * {@link #openFile} are not thread safe -- you must not call
- * {@link #release()} on the ContentProviderClient those calls are made from
- * until you are finished with the data they have returned.
+ * {@link #openFile} are not thread safe -- you must not call {@link #close()}
+ * on the ContentProviderClient those calls are made from until you are finished
+ * with the data they have returned.
*/
-public class ContentProviderClient {
+public class ContentProviderClient implements AutoCloseable {
private static final String TAG = "ContentProviderClient";
@GuardedBy("ContentProviderClient.class")
@@ -63,22 +71,23 @@
private final String mPackageName;
private final boolean mStable;
- private final CloseGuard mGuard = CloseGuard.get();
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
private long mAnrTimeout;
private NotRespondingRunnable mAnrRunnable;
- private boolean mReleased;
-
/** {@hide} */
- ContentProviderClient(
+ @VisibleForTesting
+ public ContentProviderClient(
ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
mContentResolver = contentResolver;
mContentProvider = contentProvider;
mPackageName = contentResolver.mPackageName;
+
mStable = stable;
- mGuard.open("release");
+ mCloseGuard.open("close");
}
/** {@hide} */
@@ -133,8 +142,14 @@
remoteCancellationSignal = mContentProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
- sortOrder, remoteCancellationSignal);
+ final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection,
+ selectionArgs, sortOrder, remoteCancellationSignal);
+ if ("com.google.android.gms".equals(mPackageName)) {
+ // They're casting to a concrete subclass, sigh
+ return cursor;
+ } else {
+ return new CursorWrapperInner(cursor);
+ }
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -446,29 +461,42 @@
}
/**
- * Call this to indicate to the system that the associated {@link ContentProvider} is no
- * longer needed by this {@link ContentProviderClient}.
- * @return true if this was release, false if it was already released
+ * Closes this client connection, indicating to the system that the
+ * underlying {@link ContentProvider} is no longer needed.
*/
+ @Override
+ public void close() {
+ closeInternal();
+ }
+
+ /**
+ * @deprecated replaced by {@link #close()}.
+ */
+ @Deprecated
public boolean release() {
- synchronized (this) {
- if (mReleased) {
- throw new IllegalStateException("Already released");
- }
- mReleased = true;
- mGuard.close();
+ return closeInternal();
+ }
+
+ private boolean closeInternal() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
if (mStable) {
return mContentResolver.releaseProvider(mContentProvider);
} else {
return mContentResolver.releaseUnstableProvider(mContentProvider);
}
+ } else {
+ return false;
}
}
@Override
protected void finalize() throws Throwable {
- if (mGuard != null) {
- mGuard.warnIfOpen();
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
}
}
@@ -502,4 +530,29 @@
mContentResolver.appNotRespondingViaProvider(mContentProvider);
}
}
+
+ private final class CursorWrapperInner extends CrossProcessCursorWrapper {
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ CursorWrapperInner(Cursor cursor) {
+ super(cursor);
+ mCloseGuard.open("close");
+ }
+
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ super.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+ }
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9d0ebc2..684a85e 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -20,6 +20,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
@@ -47,11 +49,11 @@
import android.util.EventLog;
import android.util.Log;
-import dalvik.system.CloseGuard;
-
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -59,9 +61,9 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* This class provides applications access to the content model.
@@ -514,8 +516,9 @@
maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
// Wrap the cursor object into CursorWrapperInner object.
- CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
- stableProvider != null ? stableProvider : acquireProvider(uri));
+ final IContentProvider provider = (stableProvider != null) ? stableProvider
+ : acquireProvider(uri);
+ final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
@@ -1609,7 +1612,7 @@
/** @hide - designated user version */
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
- ContentObserver observer, int userHandle) {
+ ContentObserver observer, @UserIdInt int userHandle) {
try {
getContentService().registerContentObserver(uri, notifyForDescendents,
observer.getContentObserver(), userHandle);
@@ -1683,7 +1686,7 @@
* @hide
*/
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork,
- int userHandle) {
+ @UserIdInt int userHandle) {
try {
getContentService().notifyChange(
uri, observer == null ? null : observer.getContentObserver(),
@@ -1824,7 +1827,7 @@
* @see #requestSync(Account, String, Bundle)
* @hide
*/
- public static void requestSyncAsUser(Account account, String authority, int userId,
+ public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
Bundle extras) {
if (extras == null) {
throw new IllegalArgumentException("Must specify extras.");
@@ -1921,7 +1924,7 @@
* @see #cancelSync(Account, String)
* @hide
*/
- public static void cancelSyncAsUser(Account account, String authority, int userId) {
+ public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
try {
getContentService().cancelSyncAsUser(account, authority, null, userId);
} catch (RemoteException e) {
@@ -1944,7 +1947,7 @@
* @see #getSyncAdapterTypes()
* @hide
*/
- public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
+ public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
try {
return getContentService().getSyncAdapterTypesAsUser(userId);
} catch (RemoteException e) {
@@ -1956,8 +1959,9 @@
* @hide
* Returns the package names of syncadapters that match a given user and authority.
*/
+ @TestApi
public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
- int userId) {
+ @UserIdInt int userId) {
try {
return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
} catch (RemoteException e) {
@@ -1987,7 +1991,7 @@
* @hide
*/
public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
- int userId) {
+ @UserIdInt int userId) {
try {
return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
} catch (RemoteException e) {
@@ -2013,7 +2017,7 @@
* @hide
*/
public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
- int userId) {
+ @UserIdInt int userId) {
try {
getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
} catch (RemoteException e) {
@@ -2172,7 +2176,8 @@
* @see #getIsSyncable(Account, String)
* @hide
*/
- public static int getIsSyncableAsUser(Account account, String authority, int userId) {
+ public static int getIsSyncableAsUser(Account account, String authority,
+ @UserIdInt int userId) {
try {
return getContentService().getIsSyncableAsUser(account, authority, userId);
} catch (RemoteException e) {
@@ -2215,7 +2220,7 @@
* @see #getMasterSyncAutomatically()
* @hide
*/
- public static boolean getMasterSyncAutomaticallyAsUser(int userId) {
+ public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
try {
return getContentService().getMasterSyncAutomaticallyAsUser(userId);
} catch (RemoteException e) {
@@ -2239,7 +2244,7 @@
* @see #setMasterSyncAutomatically(boolean)
* @hide
*/
- public static void setMasterSyncAutomaticallyAsUser(boolean sync, int userId) {
+ public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
try {
getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
} catch (RemoteException e) {
@@ -2319,7 +2324,7 @@
* @see #getCurrentSyncs()
* @hide
*/
- public static List<SyncInfo> getCurrentSyncsAsUser(int userId) {
+ public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
try {
return getContentService().getCurrentSyncsAsUser(userId);
} catch (RemoteException e) {
@@ -2347,7 +2352,7 @@
* @hide
*/
public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
- int userId) {
+ @UserIdInt int userId) {
try {
return getContentService().getSyncStatusAsUser(account, authority, null, userId);
} catch (RemoteException e) {
@@ -2371,7 +2376,8 @@
* @see #requestSync(Account, String, Bundle)
* @hide
*/
- public static boolean isSyncPendingAsUser(Account account, String authority, int userId) {
+ public static boolean isSyncPendingAsUser(Account account, String authority,
+ @UserIdInt int userId) {
try {
return getContentService().isSyncPendingAsUser(account, authority, null, userId);
} catch (RemoteException e) {
@@ -2503,41 +2509,31 @@
private final class CursorWrapperInner extends CrossProcessCursorWrapper {
private final IContentProvider mContentProvider;
- public static final String TAG="CursorWrapperInner";
+ private final AtomicBoolean mProviderReleased = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
- private boolean mProviderReleased;
- CursorWrapperInner(Cursor cursor, IContentProvider icp) {
+ CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
super(cursor);
- mContentProvider = icp;
+ mContentProvider = contentProvider;
mCloseGuard.open("close");
}
@Override
public void close() {
+ mCloseGuard.close();
super.close();
- ContentResolver.this.releaseProvider(mContentProvider);
- mProviderReleased = true;
- if (mCloseGuard != null) {
- mCloseGuard.close();
+ if (mProviderReleased.compareAndSet(false, true)) {
+ ContentResolver.this.releaseProvider(mContentProvider);
}
}
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
-
- if (!mProviderReleased && mContentProvider != null) {
- // Even though we are using CloseGuard, log this anyway so that
- // application developers always see the message in the log.
- Log.w(TAG, "Cursor finalized without prior close()");
- ContentResolver.this.releaseProvider(mContentProvider);
- }
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
@@ -2546,7 +2542,7 @@
private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
private final IContentProvider mContentProvider;
- private boolean mProviderReleased;
+ private final AtomicBoolean mProviderReleased = new AtomicBoolean();
ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
super(pfd);
@@ -2555,9 +2551,8 @@
@Override
public void releaseResources() {
- if (!mProviderReleased) {
+ if (mProviderReleased.compareAndSet(false, true)) {
ContentResolver.this.releaseProvider(mContentProvider);
- mProviderReleased = true;
}
}
}
@@ -2584,7 +2579,9 @@
private static IContentService sContentService;
private final Context mContext;
+
final String mPackageName;
+
private static final String TAG = "ContentResolver";
/** @hide */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 38a4475..a6036bb 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -30,6 +30,8 @@
import android.annotation.StyleRes;
import android.annotation.StyleableRes;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
@@ -326,10 +328,30 @@
*/
public static final int BIND_NOT_VISIBLE = 0x40000000;
- /** Return an AssetManager instance for your application's package. */
+ /**
+ * Returns an AssetManager instance for the application's package.
+ * <p>
+ * <strong>Note:</strong> Implementations of this method should return
+ * an AssetManager instance that is consistent with the Resources instance
+ * returned by {@link #getResources()}. For example, they should share the
+ * same {@link Configuration} object.
+ *
+ * @return an AssetManager instance for the application's package
+ * @see #getResources()
+ */
public abstract AssetManager getAssets();
- /** Return a Resources instance for your application's package. */
+ /**
+ * Returns a Resources instance for the application's package.
+ * <p>
+ * <strong>Note:</strong> Implementations of this method should return
+ * a Resources instance that is consistent with the AssetManager instance
+ * returned by {@link #getAssets()}. For example, they should share the
+ * same {@link Configuration} object.
+ *
+ * @return a Resources instance for the application's package
+ * @see #getAssets()
+ */
public abstract Resources getResources();
/** Return PackageManager instance to find global package information. */
@@ -3947,7 +3969,8 @@
*
* @hide
*/
- public abstract int getUserId();
+ @TestApi
+ public abstract @UserIdInt int getUserId();
/**
* Return a new Context object for the current Context but whose resources
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 1a3d262..c99ddc8 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -82,8 +82,7 @@
}
@Override
- public Resources getResources()
- {
+ public Resources getResources() {
return mBase.getResources();
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a27d1cb..35cd2be 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3604,6 +3604,15 @@
public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID";
/**
+ * An int representing the task id to be retrieved. This is used when a launch from recents is
+ * intercepted by another action such as credentials confirmation to remember which task should
+ * be resumed when complete.
+ *
+ * @hide
+ */
+ public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID";
+
+ /**
* An Intent[] describing additional, alternate choices you would like shown with
* {@link #ACTION_CHOOSER}.
*
@@ -3687,6 +3696,20 @@
public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
/**
+ * A {@link IntentSender} to start after ephemeral installation success.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_EPHEMERAL_SUCCESS = "android.intent.extra.EPHEMERAL_SUCCESS";
+
+ /**
+ * A {@link IntentSender} to start after ephemeral installation failure.
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_EPHEMERAL_FAILURE = "android.intent.extra.EPHEMERAL_FAILURE";
+
+ /**
* A Bundle forming a mapping of potential target package names to different extras Bundles
* to add to the default intent extras in {@link #EXTRA_INTENT} when used with
* {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not
@@ -4154,6 +4177,21 @@
public static final int FLAG_GRANT_PREFIX_URI_PERMISSION = 0x00000080;
/**
+ * Internal flag used to indicate that a system component has done their
+ * homework and verified that they correctly handle packages and components
+ * that come and go over time. In particular:
+ * <ul>
+ * <li>Apps installed on external storage, which will appear to be
+ * uninstalled while the the device is ejected.
+ * <li>Apps with encryption unaware components, which will appear to not
+ * exist while the device is locked.
+ * </ul>
+ *
+ * @hide
+ */
+ public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
+
+ /**
* If set, the new activity is not kept in the history stack. As soon as
* the user navigates away from it, the activity is finished. This may also
* be set with the {@link android.R.styleable#AndroidManifestActivity_noHistory
@@ -4419,6 +4457,13 @@
public static final int FLAG_ACTIVITY_RETAIN_IN_RECENTS = 0x00002000;
/**
+ * This flag is only used in the multi-window mode. The new activity will be displayed on
+ * the other side than the one that is launching it. This can only be used in conjunction with
+ * {@link #FLAG_ACTIVITY_NEW_TASK}.
+ */
+ public static final int FLAG_ACTIVITY_LAUNCH_TO_SIDE = 0x00001000;
+
+ /**
* If set, when sending a broadcast only registered receivers will be
* called -- no BroadcastReceiver components will be launched.
*/
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0cb0e9f..dedf07f5 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -276,6 +276,35 @@
*/
public static final int FLAG_RESUME_WHILE_PAUSING = 0x4000;
/**
+ * Bit in {@link #flags} indicating that this activity should be run with VR mode enabled.
+ *
+ * {@see android.app.Activity#setVrMode(boolean)}.
+ */
+ public static final int FLAG_ENABLE_VR_MODE = 0x8000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is resizeable to any dimension.
+ * See {@link android.R.attr#resizeableActivity}.
+ * @hide
+ */
+ public static final int FLAG_RESIZEABLE = 0x10000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of
+ * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}.
+ * @hide
+ */
+ public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000;
+
+ /**
+ * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
+ * in a task/stack whose activities are normally not focusable.
+ * See android.R.attr#alwaysFocusable.
+ * @hide
+ */
+ public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
+
+ /**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
* android.R.attr#systemUserOnly attribute.
@@ -664,20 +693,6 @@
*/
public String parentActivityName;
- /**
- * Value indicating if the activity is resizeable to any dimension.
- * See {@link android.R.attr#resizeableActivity}.
- * @hide
- */
- public boolean resizeable;
-
- /**
- * Value indicating if the activity is supports picture-in-picture form of multi-window mode.
- * See {@link android.R.attr#supportsPictureInPicture}.
- * @hide
- */
- public boolean supportsPip;
-
/** @hide */
public static final int LOCK_TASK_LAUNCH_MODE_DEFAULT = 0;
/** @hide */
@@ -729,8 +744,6 @@
uiOptions = orig.uiOptions;
parentActivityName = orig.parentActivityName;
maxRecents = orig.maxRecents;
- resizeable = orig.resizeable;
- supportsPip = orig.supportsPip;
lockTaskLaunchMode = orig.lockTaskLaunchMode;
layout = orig.layout;
}
@@ -785,7 +798,6 @@
pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
}
if ((flags&DUMP_FLAG_DETAILS) != 0) {
- pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
pw.println(prefix + "lockTaskLaunchMode="
+ lockTaskLaunchModeToString(lockTaskLaunchMode));
}
@@ -823,8 +835,6 @@
dest.writeString(parentActivityName);
dest.writeInt(persistableMode);
dest.writeInt(maxRecents);
- dest.writeInt(resizeable ? 1 : 0);
- dest.writeInt(supportsPip ? 1 : 0);
dest.writeInt(lockTaskLaunchMode);
if (layout != null) {
dest.writeInt(1);
@@ -865,8 +875,6 @@
parentActivityName = source.readString();
persistableMode = source.readInt();
maxRecents = source.readInt();
- resizeable = (source.readInt() == 1);
- supportsPip = (source.readInt() == 1);
lockTaskLaunchMode = source.readInt();
if (source.readInt() == 1) {
layout = new Layout(source);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b499af5..0168908 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.annotation.TestApi;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
@@ -382,6 +383,12 @@
public static final int FLAG_HARDWARE_ACCELERATED = 1<<29;
/**
+ * Value for {@link #flags}: true if this application's package is in
+ * the suspended state.
+ */
+ public static final int FLAG_SUSPENDED = 1<<30;
+
+ /**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
@@ -486,13 +493,6 @@
public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
/**
- * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
- * and for most purposes is considered as not installed.
- * {@hide}
- */
- public static final int PRIVATE_FLAG_EPHEMERAL = 1<<8;
-
- /**
* When set, at least one component inside this application is encryption aware.
*
* @hide
@@ -500,6 +500,21 @@
public static final int PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE = 1 << 8;
/**
+ * Value for {@link #flags}: {@code true} if the application is blocked via restrictions
+ * and for most purposes is considered as not installed.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9;
+
+ /**
+ * When set, signals that the application is required for the system user and should not be
+ * uninstalled.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10;
+
+ /**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
@@ -789,7 +804,12 @@
public boolean hasRtlSupport() {
return (flags & FLAG_SUPPORTS_RTL) == FLAG_SUPPORTS_RTL;
}
-
+
+ /** {@hide} */
+ public boolean hasCode() {
+ return (flags & FLAG_HAS_CODE) != 0;
+ }
+
public static class DisplayNameComparator
implements Comparator<ApplicationInfo> {
public DisplayNameComparator(PackageManager pm) {
@@ -1055,6 +1075,7 @@
/**
* @hide
*/
+ @TestApi
public boolean isSystemApp() {
return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
@@ -1062,6 +1083,7 @@
/**
* @hide
*/
+ @TestApi
public boolean isPrivilegedApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
@@ -1111,6 +1133,13 @@
/**
* @hide
*/
+ public boolean isRequiredForSystemUser() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER) != 0;
+ }
+
+ /**
+ * @hide
+ */
@Override protected ApplicationInfo getApplicationInfo() {
return this;
}
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index 084bc18..e542589 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -51,6 +51,11 @@
*/
public static int GET_IMES = 1 << 2;
+ /**
+ * Return all apps that are flagged as required for the system user.
+ */
+ public static int GET_REQUIRED_FOR_SYSTEM_USER = 1 << 3;
+
private final IPackageManager mPackageManager;
private List<ApplicationInfo> mAllApps;
@@ -73,6 +78,7 @@
boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
boolean imes = (flags & GET_IMES) > 0;
+ boolean requiredForSystemUser = (flags & GET_REQUIRED_FOR_SYSTEM_USER) > 0;
if (mAllApps == null) {
mAllApps = getAllApps(user.getIdentifier());
}
@@ -143,6 +149,18 @@
}
}
+ if (requiredForSystemUser) {
+ final int allAppsSize = mAllApps.size();
+ for (int i = 0; i < allAppsSize; i++) {
+ final ApplicationInfo appInfo = mAllApps.get(i);
+ if (systemAppsOnly && !appInfo.isSystemApp()) {
+ continue;
+ }
+ if (appInfo.isRequiredForSystemUser()) {
+ result.add(appInfo.packageName);
+ }
+ }
+ }
return result;
}
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index a295cc5..63a163d 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -16,6 +16,7 @@
package android.content.pm;
+import android.content.ComponentName;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -148,6 +149,11 @@
return banner != 0 ? banner : applicationInfo.banner;
}
+ /** {@hide} */
+ public ComponentName getComponentName() {
+ return new ComponentName(packageName, name);
+ }
+
protected void dumpFront(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
if (processName != null && !packageName.equals(processName)) {
diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java
new file mode 100644
index 0000000..afb4c30
--- /dev/null
+++ b/core/java/android/content/pm/EphemeralResolveInfo.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Information about an ephemeral application.
+ * @hide
+ */
+@SystemApi
+public final class EphemeralResolveInfo implements Parcelable {
+ /** Algorithm that will be used to generate the domain digest */
+ public static final String SHA_ALGORITHM = "SHA-256";
+
+ /** Full digest of the domain hash */
+ private final byte[] mDigestBytes;
+ /** The first 4 bytes of the domain hash */
+ private final int mDigestPrefix;
+ private final String mPackageName;
+ /** The filters used to match domain */
+ private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
+
+ public EphemeralResolveInfo(@NonNull Uri uri, @NonNull String packageName,
+ @NonNull List<IntentFilter> filters) {
+ // validate arguments
+ if (uri == null
+ || packageName == null
+ || filters == null
+ || filters.size() == 0) {
+ throw new IllegalArgumentException();
+ }
+
+ mDigestBytes = generateDigest(uri);
+ mDigestPrefix =
+ mDigestBytes[0] << 24
+ | mDigestBytes[1] << 16
+ | mDigestBytes[2] << 8
+ | mDigestBytes[3] << 0;
+ mFilters.addAll(filters);
+ mPackageName = packageName;
+ }
+
+ EphemeralResolveInfo(Parcel in) {
+ mDigestBytes = in.createByteArray();
+ mDigestPrefix = in.readInt();
+ mPackageName = in.readString();
+ in.readList(mFilters, null /*loader*/);
+ }
+
+ public byte[] getDigestBytes() {
+ return mDigestBytes;
+ }
+
+ public int getDigestPrefix() {
+ return mDigestPrefix;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public List<IntentFilter> getFilters() {
+ return mFilters;
+ }
+
+ private static byte[] generateDigest(Uri uri) {
+ try {
+ final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
+ final byte[] hostBytes = uri.getHost().getBytes();
+ return digest.digest(hostBytes);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException("could not find digest algorithm");
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeByteArray(mDigestBytes);
+ out.writeInt(mDigestPrefix);
+ out.writeString(mPackageName);
+ out.writeList(mFilters);
+ }
+
+ public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR
+ = new Parcelable.Creator<EphemeralResolveInfo>() {
+ public EphemeralResolveInfo createFromParcel(Parcel in) {
+ return new EphemeralResolveInfo(in);
+ }
+
+ public EphemeralResolveInfo[] newArray(int size) {
+ return new EphemeralResolveInfo[size];
+ }
+ };
+
+ /** @hide */
+ public static final class EphemeralResolveIntentInfo extends IntentFilter {
+ private final EphemeralResolveInfo mResolveInfo;
+
+ public EphemeralResolveIntentInfo(@NonNull IntentFilter orig,
+ @NonNull EphemeralResolveInfo resolveInfo) {
+ super(orig);
+ this.mResolveInfo = resolveInfo;
+ }
+
+ public EphemeralResolveInfo getEphemeralResolveInfo() {
+ return mResolveInfo;
+ }
+ }
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index b947a2b..39f59554 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -285,6 +285,8 @@
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
+ boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId);
+
/**
* Backup/restore support - only the system uid may use these.
*/
@@ -521,4 +523,6 @@
boolean setEphemeralApplicationCookie(String packageName, in byte[] cookie, int userId);
Bitmap getEphemeralApplicationIcon(String packageName, int userId);
boolean isEphemeralApplication(String packageName, int userId);
+
+ boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
}
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
deleted file mode 100644
index e7dc764..0000000
--- a/core/java/android/content/pm/ManifestDigest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 com.android.internal.util.HexDump;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.DigestInputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import libcore.io.IoUtils;
-
-/**
- * Represents the manifest digest for a package. This is suitable for comparison
- * of two packages to know whether the manifests are identical.
- *
- * @hide
- */
-@SystemApi
-public class ManifestDigest implements Parcelable {
- private static final String TAG = "ManifestDigest";
-
- /** The digest of the manifest in our preferred order. */
- private final byte[] mDigest;
-
- /** What we print out first when toString() is called. */
- private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
-
- /** Digest algorithm to use. */
- private static final String DIGEST_ALGORITHM = "SHA-256";
-
- ManifestDigest(byte[] digest) {
- mDigest = digest;
- }
-
- private ManifestDigest(Parcel source) {
- mDigest = source.createByteArray();
- }
-
- static ManifestDigest fromInputStream(InputStream fileIs) {
- if (fileIs == null) {
- return null;
- }
-
- final MessageDigest md;
- try {
- md = MessageDigest.getInstance(DIGEST_ALGORITHM);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
- }
-
- final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
- try {
- byte[] readBuffer = new byte[8192];
- while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
- // not using
- }
- } catch (IOException e) {
- Slog.w(TAG, "Could not read manifest");
- return null;
- } finally {
- IoUtils.closeQuietly(dis);
- }
-
- final byte[] digest = md.digest();
- return new ManifestDigest(digest);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof ManifestDigest)) {
- return false;
- }
-
- final ManifestDigest other = (ManifestDigest) o;
-
- return this == other || Arrays.equals(mDigest, other.mDigest);
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(mDigest);
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
- + (mDigest.length * 3) + 1);
-
- sb.append(TO_STRING_PREFIX);
-
- final int N = mDigest.length;
- for (int i = 0; i < N; i++) {
- final byte b = mDigest[i];
- HexDump.appendByteAsHex(sb, b, false);
- sb.append(',');
- }
- sb.append('}');
-
- return sb.toString();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeByteArray(mDigest);
- }
-
- public static final Parcelable.Creator<ManifestDigest> CREATOR
- = new Parcelable.Creator<ManifestDigest>() {
- public ManifestDigest createFromParcel(Parcel source) {
- return new ManifestDigest(source);
- }
-
- public ManifestDigest[] newArray(int size) {
- return new ManifestDigest[size];
- }
- };
-
-}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d6d395b..3283005 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1042,12 +1042,6 @@
}
/** {@hide} */
- @SystemApi
- public void setInstallFlagsQuick() {
- installFlags |= PackageManager.INSTALL_QUICK;
- }
-
- /** {@hide} */
public void dump(IndentingPrintWriter pw) {
pw.printPair("mode", mode);
pw.printHexPair("installFlags", installFlags);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a822150..9d94b74 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -27,6 +27,8 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
+import android.annotation.TestApi;
import android.annotation.XmlRes;
import android.app.PackageDeleteObserver;
import android.app.PackageInstallObserver;
@@ -47,10 +49,8 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.VolumeInfo;
-import android.provider.Settings;
import android.util.AndroidException;
-import android.util.Log;
import com.android.internal.util.ArrayUtils;
import java.io.File;
@@ -95,6 +95,109 @@
}
/**
+ * As a guiding principle:
+ * <p>
+ * {@code GET_} flags are used to request additional data that may have been
+ * elided to save wire space.
+ * <p>
+ * {@code MATCH_} flags are used to include components or packages that
+ * would have otherwise been omitted from a result set by current system
+ * state.
+ */
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_ACTIVITIES,
+ GET_RECEIVERS,
+ GET_SERVICES,
+ GET_PROVIDERS,
+ GET_INSTRUMENTATION,
+ GET_INTENT_FILTERS,
+ GET_SIGNATURES,
+ GET_META_DATA,
+ GET_GIDS,
+ GET_SHARED_LIBRARY_FILES,
+ GET_URI_PERMISSION_PATTERNS,
+ GET_PERMISSIONS,
+ GET_CONFIGURATIONS,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PackageInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ApplicationInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_ALL,
+ MATCH_DEFAULT_ONLY,
+ MATCH_ENCRYPTION_AWARE,
+ MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ MATCH_ENCRYPTION_UNAWARE,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ComponentInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ GET_SHARED_LIBRARY_FILES,
+ GET_RESOLVED_FILTER,
+ MATCH_UNINSTALLED_PACKAGES,
+ MATCH_DISABLED_COMPONENTS,
+ MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+ MATCH_ALL,
+ MATCH_DEFAULT_ONLY,
+ MATCH_ENCRYPTION_AWARE,
+ MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+ MATCH_ENCRYPTION_UNAWARE,
+ MATCH_SYSTEM_ONLY,
+ MATCH_DEBUG_TRIAGED_MISSING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ResolveInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PermissionGroupInfoFlags {}
+
+ /** @hide */
+ @IntDef(flag = true, value = {
+ GET_META_DATA,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InstrumentationInfoFlags {}
+
+ /**
* {@link PackageInfo} flag: return information about
* activities in the package in {@link PackageInfo#activities}.
*/
@@ -163,9 +266,15 @@
public static final int GET_GIDS = 0x00000100;
/**
+ * @deprecated replaced with {@link #MATCH_DISABLED_COMPONENTS}
+ */
+ @Deprecated
+ public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+
+ /**
* {@link PackageInfo} flag: include disabled components in the returned info.
*/
- public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+ public static final int MATCH_DISABLED_COMPONENTS = 0x00000200;
/**
* {@link ApplicationInfo} flag: return the
@@ -192,6 +301,12 @@
public static final int GET_PERMISSIONS = 0x00001000;
/**
+ * @deprecated replaced with {@link #MATCH_UNINSTALLED_PACKAGES}
+ */
+ @Deprecated
+ public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+
+ /**
* Flag parameter to retrieve some information about all applications (even
* uninstalled ones) which have data directories. This state could have
* resulted if applications have been deleted with flag
@@ -201,7 +316,7 @@
* Note: this flag may cause less information about currently installed
* applications to be returned.
*/
- public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+ public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
/**
* {@link PackageInfo} flag: return information about
@@ -213,12 +328,18 @@
public static final int GET_CONFIGURATIONS = 0x00004000;
/**
+ * @deprecated replaced with {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}.
+ */
+ @Deprecated
+ public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+
+ /**
* {@link PackageInfo} flag: include disabled components which are in
* that state only because of {@link #COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED}
* in the returned info. Note that if you set this flag, applications
* that are in this disabled state will be reported as enabled.
*/
- public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+ public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
/**
* Resolution and querying flag: if set, only filters that support the
@@ -229,28 +350,55 @@
public static final int MATCH_DEFAULT_ONLY = 0x00010000;
/**
- * Querying flag: if set and if the platform is doing any filtering of the results, then
- * the filtering will not happen. This is a synonym for saying that all results should
- * be returned.
+ * Querying flag: if set and if the platform is doing any filtering of the
+ * results, then the filtering will not happen. This is a synonym for saying
+ * that all results should be returned.
+ * <p>
+ * <em>This flag should be used with extreme care.</em>
*/
public static final int MATCH_ALL = 0x00020000;
/**
- * {@link PackageInfo} flag: include components which aren't encryption
- * aware in the returned info, regardless of the current user state.
+ * Querying flag: include only components which are encryption unaware in
+ * the returned info, regardless of the current user state.
*/
- public static final int GET_ENCRYPTION_UNAWARE_COMPONENTS = 0x00040000;
+ public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
/**
- * {@link PackageInfo} flag: return components that are marked as
- * {@link ComponentInfo#encryptionAware}, unless
- * {@link #GET_ENCRYPTION_UNAWARE_COMPONENTS} is also specified.
- * <p>
- * This flag is for internal use only.
+ * Querying flag: include only components which are encryption aware in the
+ * returned info, regardless of the current user state.
+ */
+ public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
+
+ /**
+ * Querying flag: include both encryption aware and unaware components in
+ * the returned info, regardless of the current user state.
+ */
+ public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
+ | MATCH_ENCRYPTION_UNAWARE;
+
+ /**
+ * Querying flag: include only components from applications that are marked
+ * with {@link ApplicationInfo#FLAG_SYSTEM}.
+ */
+ public static final int MATCH_SYSTEM_ONLY = 0x00100000;
+
+ /**
+ * Internal flag used to indicate that a system component has done their
+ * homework and verified that they correctly handle packages and components
+ * that come and go over time. In particular:
+ * <ul>
+ * <li>Apps installed on external storage, which will appear to be
+ * uninstalled while the the device is ejected.
+ * <li>Apps with encryption unaware components, which will appear to not
+ * exist while the device is locked.
+ * </ul>
*
+ * @see #MATCH_UNINSTALLED_PACKAGES
+ * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
* @hide
*/
- public static final int MATCH_ENCRYPTION_AWARE_ONLY = 0x00080000;
+ public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
/**
* Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
@@ -457,19 +605,11 @@
/**
* Flag parameter for {@link #installPackage} to indicate that this package is
- * to be installed quickly.
- *
- * @hide
- */
- public static final int INSTALL_QUICK = 0x00000800;
-
- /**
- * Flag parameter for {@link #installPackage} to indicate that this package is
* to be installed as a lightweight "ephemeral" app.
*
* @hide
*/
- public static final int INSTALL_EPHEMERAL = 0x00001000;
+ public static final int INSTALL_EPHEMERAL = 0x00000800;
/**
* Flag parameter for
@@ -1763,6 +1903,13 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports picture-in-picture multi-window mode.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports creating secondary users and managed profiles via
* {@link DevicePolicyManager}.
*/
@@ -1802,7 +1949,6 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: This device supports ethernet.
- * @hide
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
@@ -1831,6 +1977,16 @@
public static final String FEATURE_MIDI = "android.software.midi";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device implements a an optimized mode for virtual reality (VR) applications that handles
+ * stereoscopic rendering of notifications, and may potentially also include optimizations to
+ * reduce latency in the graphics, display, and sensor stacks. Presence of this feature
+ * also indicates that the VrCore library is included on this device.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VR_MODE = "android.software.vr.mode";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
@@ -2073,9 +2229,6 @@
/**
* Retrieve overall information about an application package that is
* installed on the system.
- * <p>
- * Throws {@link NameNotFoundException} if a package with the given name can
- * not be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2093,6 +2246,8 @@
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
* @see #GET_ACTIVITIES
* @see #GET_GIDS
* @see #GET_CONFIGURATIONS
@@ -2104,16 +2259,13 @@
* @see #GET_SIGNATURES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract PackageInfo getPackageInfo(String packageName, int flags)
+ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
* @hide
* Retrieve overall information about an application package that is
* installed on the system.
- * <p>
- * Throws {@link NameNotFoundException} if a package with the given name can
- * not be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2132,6 +2284,8 @@
* applications (which includes installed applications as well as
* applications with data directory i.e. applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
* @see #GET_ACTIVITIES
* @see #GET_GIDS
* @see #GET_CONFIGURATIONS
@@ -2144,8 +2298,8 @@
* @see #GET_UNINSTALLED_PACKAGES
*/
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
- public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
- throws NameNotFoundException;
+ public abstract PackageInfo getPackageInfoAsUser(String packageName,
+ @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
/**
* Map from the current package names in use on the device to whatever
@@ -2187,9 +2341,6 @@
* through packages. The current implementation will look for a main
* activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or
* return null if no main leanback activities are found.
- * <p>
- * Throws {@link NameNotFoundException} if a package with the given name
- * cannot be found on the system.
*
* @param packageName The name of the package to inspect.
* @return Returns either a fully-qualified Intent that can be used to launch
@@ -2201,39 +2352,73 @@
/**
* Return an array of all of the secondary group-ids that have been assigned
* to a package.
- * <p>
- * Throws {@link NameNotFoundException} if a package with the given name
- * cannot be found on the system.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
* @return Returns an int array of the assigned gids, or null if there are
* none.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
public abstract int[] getPackageGids(String packageName)
throws NameNotFoundException;
/**
- * @hide Return the uid associated with the given package name for the
- * given user.
- *
- * <p>Throws {@link NameNotFoundException} if a package with the given
- * name can not be found on the system.
+ * Return an array of all of the secondary group-ids that have been assigned
+ * to a package.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- * @param userHandle The user handle identifier to look up the package under.
- *
- * @return Returns an integer uid who owns the given package name.
+ * desired package.
+ * @return Returns an int array of the assigned gids, or null if there are
+ * none.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
- public abstract int getPackageUid(String packageName, int userHandle)
+ public abstract int[] getPackageGids(String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
/**
- * Retrieve all of the information we know about a particular permission.
+ * Return the UID associated with the given package name.
*
- * <p>Throws {@link NameNotFoundException} if a permission with the given
- * name cannot be found on the system.
+ * @param packageName The full name (i.e. com.google.apps.contacts) of the
+ * desired package.
+ * @return Returns an integer UID who owns the given package name.
+ * @throws NameNotFoundException if a package with the given name can not be
+ * found on the system.
+ */
+ public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags)
+ throws NameNotFoundException;
+
+ /**
+ * Return the UID associated with the given package name.
+ *
+ * @param packageName The full name (i.e. com.google.apps.contacts) of the
+ * desired package.
+ * @param userId The user handle identifier to look up the package under.
+ * @return Returns an integer UID who owns the given package name.
+ * @throws NameNotFoundException if a package with the given name can not be
+ * found on the system.
+ * @hide
+ */
+ public abstract int getPackageUidAsUser(String packageName, @UserIdInt int userId)
+ throws NameNotFoundException;
+
+ /**
+ * Return the UID associated with the given package name.
+ *
+ * @param packageName The full name (i.e. com.google.apps.contacts) of the
+ * desired package.
+ * @param userId The user handle identifier to look up the package under.
+ * @return Returns an integer UID who owns the given package name.
+ * @throws NameNotFoundException if a package with the given name can not be
+ * found on the system.
+ * @hide
+ */
+ public abstract int getPackageUidAsUser(String packageName, @PackageInfoFlags int flags,
+ @UserIdInt int userId) throws NameNotFoundException;
+
+ /**
+ * Retrieve all of the information we know about a particular permission.
*
* @param name The fully qualified name (i.e. com.google.permission.LOGIN)
* of the permission you are interested in.
@@ -2242,16 +2427,15 @@
*
* @return Returns a {@link PermissionInfo} containing information about the
* permission.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
- public abstract PermissionInfo getPermissionInfo(String name, int flags)
+ public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
throws NameNotFoundException;
/**
* Query for all of the permissions associated with a particular group.
*
- * <p>Throws {@link NameNotFoundException} if the given group does not
- * exist.
- *
* @param group The fully qualified name (i.e. com.google.permission.LOGIN)
* of the permission group you are interested in. Use null to
* find all of the permissions not associated with a group.
@@ -2260,17 +2444,16 @@
*
* @return Returns a list of {@link PermissionInfo} containing information
* about all of the permissions in the given group.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
- int flags) throws NameNotFoundException;
+ @PermissionInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular group of
* permissions.
*
- * <p>Throws {@link NameNotFoundException} if a permission group with the given
- * name cannot be found on the system.
- *
* @param name The fully qualified name (i.e. com.google.permission_group.APPS)
* of the permission you are interested in.
* @param flags Additional option flags. Use {@link #GET_META_DATA} to
@@ -2278,9 +2461,11 @@
*
* @return Returns a {@link PermissionGroupInfo} containing information
* about the permission.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
- int flags) throws NameNotFoundException;
+ @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the known permission groups in the system.
@@ -2291,15 +2476,13 @@
* @return Returns a list of {@link PermissionGroupInfo} containing
* information about all of the known permission groups.
*/
- public abstract List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+ public abstract List<PermissionGroupInfo> getAllPermissionGroups(
+ @PermissionGroupInfoFlags int flags);
/**
* Retrieve all of the information we know about a particular
* package/application.
*
- * <p>Throws {@link NameNotFoundException} if an application with the given
- * package name cannot be found on the system.
- *
* @param packageName The full name (i.e. com.google.apps.contacts) of an
* application.
* @param flags Additional option flags. Use any combination of
@@ -2315,21 +2498,20 @@
* installed applications as well as applications
* with data directory ie applications which had been
* deleted with {@code DONT_DELETE_DATA} flag set).
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
* @see #GET_UNINSTALLED_PACKAGES
*/
public abstract ApplicationInfo getApplicationInfo(String packageName,
- int flags) throws NameNotFoundException;
+ @ApplicationInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular activity
* class.
*
- * <p>Throws {@link NameNotFoundException} if an activity with the given
- * class name cannot be found on the system.
- *
* @param component The full component name (i.e.
* com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity
* class.
@@ -2338,21 +2520,20 @@
* to modify the data (in ApplicationInfo) returned.
*
* @return {@link ActivityInfo} containing information about the activity.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*
* @see #GET_INTENT_FILTERS
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ActivityInfo getActivityInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular receiver
* class.
*
- * <p>Throws {@link NameNotFoundException} if a receiver with the given
- * class name cannot be found on the system.
- *
* @param component The full component name (i.e.
* com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver
* class.
@@ -2361,21 +2542,20 @@
* to modify the data returned.
*
* @return {@link ActivityInfo} containing information about the receiver.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*
* @see #GET_INTENT_FILTERS
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ActivityInfo getReceiverInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular service
* class.
*
- * <p>Throws {@link NameNotFoundException} if a service with the given
- * class name cannot be found on the system.
- *
* @param component The full component name (i.e.
* com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service
* class.
@@ -2384,20 +2564,19 @@
* to modify the data returned.
*
* @return ServiceInfo containing information about the service.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ServiceInfo getServiceInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve all of the information we know about a particular content
* provider class.
*
- * <p>Throws {@link NameNotFoundException} if a provider with the given
- * class name cannot be found on the system.
- *
* @param component The full component name (i.e.
* com.google.providers.media/com.google.providers.media.MediaProvider) of a
* ContentProvider class.
@@ -2406,12 +2585,14 @@
* to modify the data returned.
*
* @return ProviderInfo containing information about the service.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*
* @see #GET_META_DATA
* @see #GET_SHARED_LIBRARY_FILES
*/
public abstract ProviderInfo getProviderInfo(ComponentName component,
- int flags) throws NameNotFoundException;
+ @ComponentInfoFlags int flags) throws NameNotFoundException;
/**
* Return a List of all packages that are installed
@@ -2447,7 +2628,7 @@
* @see #GET_SIGNATURES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract List<PackageInfo> getInstalledPackages(int flags);
+ public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
/**
* Return a List of all installed packages that are currently
@@ -2480,7 +2661,7 @@
* @see #GET_UNINSTALLED_PACKAGES
*/
public abstract List<PackageInfo> getPackagesHoldingPermissions(
- String[] permissions, int flags);
+ String[] permissions, @PackageInfoFlags int flags);
/**
* Return a List of all packages that are installed on the device, for a specific user.
@@ -2519,7 +2700,8 @@
*
* @hide
*/
- public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+ public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags,
+ @UserIdInt int userId);
/**
* Check whether a particular package has been granted a particular
@@ -2831,8 +3013,9 @@
* shared user.
*
* @param sharedUserName The shared user name whose uid is to be retrieved.
- * @return Returns the uid associated with the shared user, or NameNotFoundException
- * if the shared user name is not being used by any installed packages
+ * @return Returns the UID associated with the shared user.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
* @hide
*/
public abstract int getUidForSharedUser(String sharedUserName)
@@ -2859,7 +3042,7 @@
* @see #GET_SHARED_LIBRARY_FILES
* @see #GET_UNINSTALLED_PACKAGES
*/
- public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+ public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
/**
* Gets the ephemeral applications the user recently used. Requires
@@ -2994,7 +3177,7 @@
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract ResolveInfo resolveActivity(Intent intent, int flags);
+ public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
/**
* Determine the best action to perform for a given Intent for a given user. This
@@ -3027,7 +3210,8 @@
*
* @hide
*/
- public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+ public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
+ @UserIdInt int userId);
/**
* Retrieve all activities that can be performed for the given intent.
@@ -3050,7 +3234,7 @@
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all activities that can be performed for the given intent, for a specific user.
@@ -3074,8 +3258,7 @@
* @hide
*/
public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
- int flags, int userId);
-
+ @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve a set of activities that should be presented to the user as
@@ -3107,7 +3290,7 @@
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentActivityOptions(
- ComponentName caller, Intent[] specifics, Intent intent, int flags);
+ ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
/**
* Retrieve all receivers that can handle a broadcast of the given intent.
@@ -3124,7 +3307,7 @@
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all receivers that can handle a broadcast of the given intent, for a specific
@@ -3143,8 +3326,8 @@
* @see #GET_RESOLVED_FILTER
* @hide
*/
- public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
- int flags, int userId);
+ public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+ @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Determine the best service to handle for a given Intent.
@@ -3160,7 +3343,7 @@
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract ResolveInfo resolveService(Intent intent, int flags);
+ public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
/**
* Retrieve all services that can match the given intent.
@@ -3178,7 +3361,7 @@
* @see #GET_RESOLVED_FILTER
*/
public abstract List<ResolveInfo> queryIntentServices(Intent intent,
- int flags);
+ @ResolveInfoFlags int flags);
/**
* Retrieve all services that can match the given intent for a given user.
@@ -3199,11 +3382,11 @@
* @hide
*/
public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
- int flags, int userId);
+ @ResolveInfoFlags int flags, @UserIdInt int userId);
/** {@hide} */
public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
- Intent intent, int flags, int userId);
+ Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve all providers that can match the given intent.
@@ -3217,7 +3400,8 @@
* @see #GET_INTENT_FILTERS
* @see #GET_RESOLVED_FILTER
*/
- public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
+ public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+ @ResolveInfoFlags int flags);
/**
* Find a single content provider by its base path name.
@@ -3229,7 +3413,7 @@
* else null.
*/
public abstract ProviderInfo resolveContentProvider(String name,
- int flags);
+ @ComponentInfoFlags int flags);
/**
* Find a single content provider by its base path name.
@@ -3242,7 +3426,8 @@
* else null.
* @hide
*/
- public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
+ public abstract ProviderInfo resolveContentProviderAsUser(String name,
+ @ComponentInfoFlags int flags, @UserIdInt int userId);
/**
* Retrieve content provider information.
@@ -3263,15 +3448,12 @@
* <em>If there are no matching providers, null is returned.</em>
*/
public abstract List<ProviderInfo> queryContentProviders(
- String processName, int uid, int flags);
+ String processName, int uid, @ComponentInfoFlags int flags);
/**
* Retrieve all of the information we know about a particular
* instrumentation class.
*
- * <p>Throws {@link NameNotFoundException} if instrumentation with the
- * given class name cannot be found on the system.
- *
* @param className The full name (i.e.
* com.google.apps.contacts.InstrumentList) of an
* Instrumentation class.
@@ -3279,9 +3461,11 @@
*
* @return InstrumentationInfo containing information about the
* instrumentation.
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
*/
- public abstract InstrumentationInfo getInstrumentationInfo(
- ComponentName className, int flags) throws NameNotFoundException;
+ public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+ @InstrumentationInfoFlags int flags) throws NameNotFoundException;
/**
* Retrieve information about available instrumentation code. May be used
@@ -3297,8 +3481,8 @@
* matching available Instrumentation. Returns an empty list if
* there is no instrumentation available for the given package.
*/
- public abstract List<InstrumentationInfo> queryInstrumentation(
- String targetPackage, int flags);
+ public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+ @InstrumentationInfoFlags int flags);
/**
* Retrieve an image from a package. This is a low-level API used by
@@ -3701,8 +3885,8 @@
throws NameNotFoundException;
/** @hide */
- public abstract Resources getResourcesForApplicationAsUser(String appPackageName, int userId)
- throws NameNotFoundException;
+ public abstract Resources getResourcesForApplicationAsUser(String appPackageName,
+ @UserIdInt int userId) throws NameNotFoundException;
/**
* Retrieve overall information about an application package defined
@@ -3734,14 +3918,13 @@
* @see #GET_SIGNATURES
*
*/
- public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+ public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
final PackageParser parser = new PackageParser();
final File apkFile = new File(archiveFilePath);
try {
PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
if ((flags & GET_SIGNATURES) != 0) {
parser.collectCertificates(pkg, 0);
- parser.collectManifestDigest(pkg);
}
PackageUserState state = new PackageUserState();
return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
@@ -3801,14 +3984,12 @@
* @param verificationURI The location of the supplementary verification
* file. This can be a 'file:' or a 'content:' URI. May be
* {@code null}.
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
* @param encryptionParams if the package to be installed is encrypted,
* these parameters describing the encryption and authentication
* used. May be {@code null}.
* @hide
* @deprecated Use {@link #installPackageWithVerification(Uri,
- * PackageInstallObserver, int, String, Uri, ManifestDigest,
+ * PackageInstallObserver, int, String, Uri,
* ContainerEncryptionParams)} instead. This method will
* continue to be supported but the older observer interface
* will not get additional failure details.
@@ -3816,7 +3997,7 @@
// @SystemApi
public abstract void installPackageWithVerification(Uri packageURI,
IPackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams);
/**
@@ -3905,7 +4086,7 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
public abstract void installPackageAsUser(
Uri packageURI, PackageInstallObserver observer, int flags,
- String installerPackageName, int userId);
+ String installerPackageName, @UserIdInt int userId);
/**
* Similar to
@@ -3925,8 +4106,6 @@
* @param verificationURI The location of the supplementary verification
* file. This can be a 'file:' or a 'content:' URI. May be
* {@code null}.
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
* @param encryptionParams if the package to be installed is encrypted,
* these parameters describing the encryption and authentication
* used. May be {@code null}.
@@ -3934,7 +4113,7 @@
*/
public abstract void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams);
/**
@@ -3980,7 +4159,7 @@
@RequiresPermission(anyOf = {
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
- public abstract int installExistingPackageAsUser(String packageName, int userId)
+ public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
throws NameNotFoundException;
/**
@@ -4078,7 +4257,7 @@
*
* @hide
*/
- public abstract int getIntentVerificationStatus(String packageName, int userId);
+ public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId);
/**
* Allow to change the status of a Intent Verification status for all IntentFilter of an App.
@@ -4100,8 +4279,8 @@
*
* @hide
*/
- public abstract boolean updateIntentVerificationStatus(String packageName, int status,
- int userId);
+ public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
+ @UserIdInt int userId);
/**
* Get the list of IntentFilterVerificationInfo for a specific package and User.
@@ -4141,7 +4320,8 @@
*
* @hide
*/
- public abstract String getDefaultBrowserPackageName(int userId);
+ @TestApi
+ public abstract String getDefaultBrowserPackageNameAsUser(@UserIdInt int userId);
/**
* Set the default Browser package name for a specific user.
@@ -4155,7 +4335,8 @@
*
* @hide
*/
- public abstract boolean setDefaultBrowserPackageName(String packageName, int userId);
+ public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
+ @UserIdInt int userId);
/**
* Change the installer associated with a given package. There are limitations
@@ -4214,7 +4395,7 @@
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.INTERACT_ACROSS_USERS_FULL})
public abstract void deletePackageAsUser(
- String packageName, IPackageDeleteObserver observer, int flags, int userId);
+ String packageName, IPackageDeleteObserver observer, int flags, @UserIdInt int userId);
/**
* Retrieve the package name of the application that installed a package. This identifies
@@ -4327,7 +4508,7 @@
* should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission.
*
* @param packageName The name of the package whose size information is to be retrieved
- * @param userHandle The user whose size information should be retrieved.
+ * @param userId The user whose size information should be retrieved.
* @param observer An observer callback to get notified when the operation
* is complete.
* {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)}
@@ -4338,17 +4519,17 @@
*
* @hide
*/
- public abstract void getPackageSizeInfo(String packageName, int userHandle,
+ public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId,
IPackageStatsObserver observer);
/**
- * Like {@link #getPackageSizeInfo(String, int, IPackageStatsObserver)}, but
+ * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but
* returns the size for the calling user.
*
* @hide
*/
public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
- getPackageSizeInfo(packageName, UserHandle.myUserId(), observer);
+ getPackageSizeInfoAsUser(packageName, UserHandle.myUserId(), observer);
}
/**
@@ -4396,7 +4577,7 @@
* @see #GET_SERVICES
* @see #GET_SIGNATURES
*/
- public abstract List<PackageInfo> getPreferredPackages(int flags);
+ public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
/**
* @deprecated This is a protected API that should not have been available
@@ -4427,8 +4608,8 @@
to.
* @hide
*/
- public void addPreferredActivity(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
+ public void addPreferredActivityAsUser(IntentFilter filter, int match,
+ ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -4462,7 +4643,7 @@
*/
@Deprecated
public void replacePreferredActivityAsUser(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, int userId) {
+ ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
@@ -4677,6 +4858,21 @@
throw new UnsupportedOperationException();
}
+ /**
+ * Puts the package in a suspended state, making the package un-runnable,
+ * but it doesn't remove the data or the actual package file. The application notifications
+ * will be hidden and also the application will not show up in recents.
+ *
+ * @param packageName The name of the package to set the suspended status.
+ * @param suspended If set to {@code true} than the package will be suspended, if set to
+ * {@code false} the package will be unsuspended.
+ * @param userId The user id.
+ *
+ * @hide
+ */
+ public abstract boolean setPackageSuspendedAsUser(
+ String packageName, boolean suspended, @UserIdInt int userId);
+
/** {@hide} */
public static boolean isMoveStatusFinished(int status) {
return (status < 0 || status > 100);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b79b6b6..236cf64a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -625,9 +625,7 @@
public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
public final static int PARSE_TRUSTED_OVERLAY = 1<<9;
public final static int PARSE_ENFORCE_CODE = 1<<10;
- // TODO: fix b/25118622; remove this entirely once signature processing is quick
- public final static int PARSE_SKIP_VERIFICATION = 1<<11;
- public final static int PARSE_IS_EPHEMERAL = 1<<12;
+ public final static int PARSE_IS_EPHEMERAL = 1<<11;
private static final Comparator<String> sSplitNameComparator = new SplitNameComparator();
@@ -1034,34 +1032,8 @@
}
/**
- * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
- * APK. If it successfully scanned the package and found the
- * {@code AndroidManifest.xml}, {@code true} is returned.
- */
- public void collectManifestDigest(Package pkg) throws PackageParserException {
- pkg.manifestDigest = null;
-
- // TODO: extend to gather digest for split APKs
- try {
- final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
- try {
- final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
- if (je != null) {
- pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
- }
- } finally {
- jarFile.close();
- }
- } catch (IOException | RuntimeException e) {
- throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
- "Failed to collect manifest digest");
- }
- }
-
- /**
* Collect certificates from all the APKs described in the given package,
- * populating {@link Package#mSignatures}.
- * <p>Depending upon the parser flags, this may also asserts that all APK
+ * populating {@link Package#mSignatures}. Also asserts that all APK
* contents are signed correctly and consistently.
*/
public void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
@@ -1084,10 +1056,8 @@
final boolean hasCode = (apkFlags & ApplicationInfo.FLAG_HAS_CODE) != 0;
final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0) && hasCode;
final String apkPath = apkFile.getAbsolutePath();
- final boolean skipVerification = Build.IS_DEBUGGABLE
- && ((parseFlags & PARSE_SKIP_VERIFICATION) != 0);
- boolean codeFound = skipVerification;
+ boolean codeFound = false;
StrictJarFile jarFile = null;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
@@ -1106,7 +1076,7 @@
toVerify.add(manifestEntry);
// If we're parsing an untrusted package, verify all contents
- if (!skipVerification && (parseFlags & PARSE_IS_SYSTEM) == 0) {
+ if ((parseFlags & PARSE_IS_SYSTEM) == 0) {
final Iterator<ZipEntry> i = jarFile.iterator();
while (i.hasNext()) {
final ZipEntry entry = i.next();
@@ -1150,9 +1120,6 @@
for (int i=0; i < entryCerts.length; i++) {
pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
}
- if (skipVerification) {
- break;
- }
} else {
if (!Signature.areExactMatch(pkg.mSignatures, entrySignatures)) {
throw new PackageParserException(
@@ -1218,9 +1185,7 @@
if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
// TODO: factor signature related items out of Package object
final Package tempPkg = new Package(null);
- // TODO: fix b/25118622; pass in '0' for parse flags
- collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/,
- flags & PARSE_SKIP_VERIFICATION);
+ collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
signatures = tempPkg.mSignatures;
} else {
signatures = null;
@@ -3233,12 +3198,19 @@
a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
}
- a.info.resizeable = sa.getBoolean(
- R.styleable.AndroidManifestActivity_resizeableActivity,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N);
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+ owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
+ a.info.flags |= ActivityInfo.FLAG_RESIZEABLE;
- a.info.supportsPip = a.info.resizeable ? sa.getBoolean(
- R.styleable.AndroidManifestActivity_supportsPictureInPicture, false) : false;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+ }
+ }
+
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+ a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+ }
a.info.screenOrientation = sa.getInt(
R.styleable.AndroidManifestActivity_screenOrientation,
@@ -4502,12 +4474,6 @@
/* The required account type without which this application will not function */
public String mRequiredAccountType;
- /**
- * Digest suitable for comparing whether this package's manifest is the
- * same as another.
- */
- public ManifestDigest manifestDigest;
-
public String mOverlayTarget;
public int mOverlayPriority;
public boolean mTrustedOverlay;
@@ -4883,6 +4849,11 @@
} else {
ai.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
+ if (state.suspended) {
+ ai.flags |= ApplicationInfo.FLAG_SUSPENDED;
+ } else {
+ ai.flags &= ~ApplicationInfo.FLAG_SUSPENDED;
+ }
if (state.hidden) {
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN;
} else {
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 9b28401..91fdf7f 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -29,6 +29,7 @@
public boolean notLaunched;
public boolean installed;
public boolean hidden; // Is the app restricted by owner / admin
+ public boolean suspended;
public int enabled;
public boolean blockUninstall;
@@ -43,6 +44,7 @@
public PackageUserState() {
installed = true;
hidden = false;
+ suspended = false;
enabled = COMPONENT_ENABLED_STATE_DEFAULT;
domainVerificationStatus =
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
@@ -54,6 +56,7 @@
notLaunched = o.notLaunched;
enabled = o.enabled;
hidden = o.hidden;
+ suspended = o.suspended;
lastDisableAppCaller = o.lastDisableAppCaller;
disabledComponents = o.disabledComponents != null
? new ArraySet<>(o.disabledComponents) : null;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index cfb4473..945858e6 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -24,6 +24,7 @@
import android.util.Log;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -50,6 +51,10 @@
private final List<T> mList;
+ public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+ return new ParceledListSlice<T>(Collections.<T> emptyList());
+ }
+
public ParceledListSlice(List<T> list) {
mList = list;
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a413f36..bb28bde 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -365,7 +365,7 @@
protected List<ResolveInfo> queryIntentServices(int userId) {
final PackageManager pm = mContext.getPackageManager();
return pm.queryIntentServicesAsUser(new Intent(mInterfaceName),
- PackageManager.GET_META_DATA | PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS,
+ PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
userId);
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index a5fb451..c9be6eda 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -61,6 +61,19 @@
public ProviderInfo providerInfo;
/**
+ * The ephemeral application that corresponds to this resolution match. This will
+ * only be set in specific circumstances.
+ * @hide
+ */
+ public EphemeralResolveInfo ephemeralResolveInfo;
+
+ /**
+ * A ResolveInfo that points at the ephemeral installer.
+ * @hide
+ */
+ public ResolveInfo ephemeralInstaller;
+
+ /**
* The IntentFilter that was matched for this ResolveInfo.
*/
public IntentFilter filter;
@@ -159,7 +172,8 @@
*/
public boolean handleAllWebDataURI;
- private ComponentInfo getComponentInfo() {
+ /** {@hide} */
+ public ComponentInfo getComponentInfo() {
if (activityInfo != null) return activityInfo;
if (serviceInfo != null) return serviceInfo;
if (providerInfo != null) return providerInfo;
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index e5119b6..f90d295 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.pm.ManifestDigest;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -51,12 +50,6 @@
private int mInstallerUid;
/**
- * An object that holds the digest of the package which can be used to
- * verify ownership.
- */
- private final ManifestDigest mManifestDigest;
-
- /**
* Creates verification specifications for installing with application verification.
*
* @param verificationURI The location of the supplementary verification
@@ -67,16 +60,13 @@
* May be {@code null}.
* @param originatingUid UID of the application that the install request originated
* from, or NO_UID if not present
- * @param manifestDigest an object that holds the digest of the package
- * which can be used to verify ownership. May be {@code null}.
*/
public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
- int originatingUid, ManifestDigest manifestDigest) {
+ int originatingUid) {
mVerificationURI = verificationURI;
mOriginatingURI = originatingURI;
mReferrer = referrer;
mOriginatingUid = originatingUid;
- mManifestDigest = manifestDigest;
mInstallerUid = NO_UID;
}
@@ -97,10 +87,6 @@
return mOriginatingUid;
}
- public ManifestDigest getManifestDigest() {
- return mManifestDigest;
- }
-
/** @return NO_UID when not set */
public int getInstallerUid() {
return mInstallerUid;
@@ -155,14 +141,6 @@
return false;
}
- if (mManifestDigest == null) {
- if (other.mManifestDigest != null) {
- return false;
- }
- } else if (!mManifestDigest.equals(other.mManifestDigest)) {
- return false;
- }
-
if (mInstallerUid != other.mInstallerUid) {
return false;
}
@@ -178,8 +156,7 @@
hash += 7 * (mOriginatingURI == null ? 1 : mOriginatingURI.hashCode());
hash += 11 * (mReferrer == null ? 1 : mReferrer.hashCode());
hash += 13 * mOriginatingUid;
- hash += 17 * (mManifestDigest == null ? 1 : mManifestDigest.hashCode());
- hash += 19 * mInstallerUid;
+ hash += 17 * mInstallerUid;
return hash;
}
@@ -196,8 +173,6 @@
sb.append(mReferrer.toString());
sb.append(",mOriginatingUid=");
sb.append(mOriginatingUid);
- sb.append(",mManifestDigest=");
- sb.append(mManifestDigest.toString());
sb.append(",mInstallerUid=");
sb.append(mInstallerUid);
sb.append('}');
@@ -211,7 +186,6 @@
dest.writeParcelable(mOriginatingURI, 0);
dest.writeParcelable(mReferrer, 0);
dest.writeInt(mOriginatingUid);
- dest.writeParcelable(mManifestDigest, 0);
dest.writeInt(mInstallerUid);
}
@@ -221,7 +195,6 @@
mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
mReferrer = source.readParcelable(Uri.class.getClassLoader());
mOriginatingUid = source.readInt();
- mManifestDigest = source.readParcelable(ManifestDigest.class.getClassLoader());
mInstallerUid = source.readInt();
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7669053c..7b0b98d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -16,6 +16,11 @@
package android.content.res;
+import android.annotation.AnyRes;
+import android.annotation.ArrayRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.SparseArray;
@@ -142,80 +147,95 @@
}
/**
- * Retrieve the string value associated with a particular resource
- * identifier for the current configuration / skin.
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @return the string value, or {@code null}
*/
- /*package*/ final CharSequence getResourceText(int ident) {
+ @Nullable
+ final CharSequence getResourceText(@StringRes int resId) {
synchronized (this) {
- TypedValue tmpValue = mValue;
- int block = loadResourceValue(ident, (short) 0, tmpValue, true);
- if (block >= 0) {
- if (tmpValue.type == TypedValue.TYPE_STRING) {
- return mStringBlocks[block].get(tmpValue.data);
- }
- return tmpValue.coerceToString();
+ final TypedValue outValue = mValue;
+ if (getResourceValue(resId, 0, outValue, true)) {
+ return outValue.coerceToString();
}
+ return null;
}
- return null;
}
/**
- * Retrieve the string value associated with a particular resource
- * identifier for the current configuration / skin.
+ * Retrieves the string value associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @param bagEntryId
+ * @return the string value, or {@code null}
*/
- /*package*/ final CharSequence getResourceBagText(int ident, int bagEntryId) {
+ @Nullable
+ final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
synchronized (this) {
- TypedValue tmpValue = mValue;
- int block = loadResourceBagValue(ident, bagEntryId, tmpValue, true);
- if (block >= 0) {
- if (tmpValue.type == TypedValue.TYPE_STRING) {
- return mStringBlocks[block].get(tmpValue.data);
- }
- return tmpValue.coerceToString();
+ final TypedValue outValue = mValue;
+ final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+ if (block < 0) {
+ return null;
}
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ return mStringBlocks[block].get(outValue.data);
+ }
+ return outValue.coerceToString();
}
- return null;
}
/**
- * Retrieve the string array associated with a particular resource
- * identifier.
- * @param id Resource id of the string array
+ * Retrieves the string array associated with a particular resource
+ * identifier for the current configuration.
+ *
+ * @param resId the resource identifier of the string array
+ * @return the string array, or {@code null}
*/
- /*package*/ final String[] getResourceStringArray(final int id) {
- String[] retArray = getArrayStringResource(id);
- return retArray;
+ @Nullable
+ final String[] getResourceStringArray(@ArrayRes int resId) {
+ return getArrayStringResource(resId);
}
-
- /*package*/ final boolean getResourceValue(int ident,
- int density,
- TypedValue outValue,
- boolean resolveRefs)
- {
- int block = loadResourceValue(ident, (short) density, outValue, resolveRefs);
- if (block >= 0) {
- if (outValue.type != TypedValue.TYPE_STRING) {
- return true;
- }
+ /**
+ * Populates {@code outValue} with the data associated a particular
+ * resource identifier for the current configuration.
+ *
+ * @param resId the resource identifier to load
+ * @param densityDpi the density bucket for which to load the resource
+ * @param outValue the typed value in which to put the data
+ * @param resolveRefs {@code true} to resolve references, {@code false}
+ * to leave them unresolved
+ * @return {@code true} if the data was loaded into {@code outValue},
+ * {@code false} otherwise
+ */
+ final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+ boolean resolveRefs) {
+ final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
+ }
+ if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = mStringBlocks[block].get(outValue.data);
- return true;
}
- return false;
+ return true;
}
/**
* Retrieve the text array associated with a particular resource
* identifier.
- * @param id Resource id of the string array
+ *
+ * @param resId the resource id of the string array
*/
- /*package*/ final CharSequence[] getResourceTextArray(final int id) {
- int[] rawInfoArray = getArrayStringInfo(id);
- int rawInfoArrayLen = rawInfoArray.length;
+ final CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+ final int[] rawInfoArray = getArrayStringInfo(resId);
+ final int rawInfoArrayLen = rawInfoArray.length;
final int infoArrayLen = rawInfoArrayLen / 2;
int block;
int index;
- CharSequence[] retArray = new CharSequence[infoArrayLen];
+ final CharSequence[] retArray = new CharSequence[infoArrayLen];
for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
block = rawInfoArray[i];
index = rawInfoArray[i + 1];
@@ -223,32 +243,45 @@
}
return retArray;
}
-
- /*package*/ final boolean getThemeValue(long theme, int ident,
- TypedValue outValue, boolean resolveRefs) {
- int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
- if (block >= 0) {
- if (outValue.type != TypedValue.TYPE_STRING) {
- return true;
- }
- StringBlock[] blocks = mStringBlocks;
- if (blocks == null) {
- ensureStringBlocks();
- blocks = mStringBlocks;
- }
- outValue.string = blocks[block].get(outValue.data);
- return true;
+
+ /**
+ * Populates {@code outValue} with the data associated with a particular
+ * resource identifier for the current configuration. Resolves theme
+ * attributes against the specified theme.
+ *
+ * @param theme the native pointer of the theme
+ * @param resId the resource identifier to load
+ * @param outValue the typed value in which to put the data
+ * @param resolveRefs {@code true} to resolve references, {@code false}
+ * to leave them unresolved
+ * @return {@code true} if the data was loaded into {@code outValue},
+ * {@code false} otherwise
+ */
+ final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+ boolean resolveRefs) {
+ final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+ if (block < 0) {
+ return false;
}
- return false;
+ if (outValue.type == TypedValue.TYPE_STRING) {
+ final StringBlock[] blocks = ensureStringBlocks();
+ outValue.string = blocks[block].get(outValue.data);
+ }
+ return true;
}
- /*package*/ final void ensureStringBlocks() {
- if (mStringBlocks == null) {
- synchronized (this) {
- if (mStringBlocks == null) {
- makeStringBlocks(sSystem.mStringBlocks);
- }
+ /**
+ * Ensures the string blocks are loaded.
+ *
+ * @return the string blocks
+ */
+ @NonNull
+ final StringBlock[] ensureStringBlocks() {
+ synchronized (this) {
+ if (mStringBlocks == null) {
+ makeStringBlocks(sSystem.mStringBlocks);
}
+ return mStringBlocks;
}
}
@@ -698,6 +731,18 @@
*/
public native final String[] getLocales();
+ /**
+ * Same as getLocales(), except that locales that are only provided by the system (i.e. those
+ * present in framework-res.apk or its overlays) will not be listed.
+ *
+ * For example, if the "system" assets support English, French, and German, and the additional
+ * assets support Cherokee and French, getLocales() would return
+ * [Cherokee, English, French, German], while getNonSystemLocales() would return
+ * [Cherokee, French].
+ * {@hide}
+ */
+ public native final String[] getNonSystemLocales();
+
/** {@hide} */
public native final Configuration[] getSizeConfigurations();
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index cdca8698..7b56eeb 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -151,8 +151,9 @@
private boolean mPreloading;
+ // Cyclical cache used for recently-accessed XML files.
private int mLastCachedXmlBlockIndex = -1;
- private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 };
+ private final String[] mCachedXmlBlockFiles = new String[4];
private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
final AssetManager mAssets;
@@ -160,6 +161,7 @@
final DisplayMetrics mMetrics = new DisplayMetrics();
private final Configuration mConfiguration = new Configuration();
+ private Locale mResolvedLocale = null;
private PluralRules mPluralRule;
private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -315,6 +317,16 @@
}
/**
+ * Return the Locale resulting from locale negotiation between the Resources and the
+ * Configuration objects used to construct the Resources. The locale is used for retrieving
+ * resources as well as for determining plural rules.
+ */
+ @NonNull
+ public Locale getResolvedLocale() {
+ return mResolvedLocale;
+ }
+
+ /**
* Return the string value associated with a particular resource ID. The
* returned object will be a String if this is a plain string; it will be
* some other type of CharSequence if it is styled.
@@ -378,7 +390,7 @@
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
+ mPluralRule = PluralRules.forLocale(mResolvedLocale);
}
return mPluralRule;
}
@@ -441,7 +453,7 @@
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
+ return String.format(mResolvedLocale, raw, formatArgs);
}
/**
@@ -472,7 +484,7 @@
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
+ return String.format(mResolvedLocale, raw, formatArgs);
}
/**
@@ -855,6 +867,11 @@
try {
getValueForDensity(id, density, value, true);
+ // If the drawable's XML lives in our current density qualifier,
+ // it's okay to use a scaled version from the cache. Otherwise, we
+ // need to actually load the drawable from XML.
+ final boolean useCache = value.density == mMetrics.densityDpi;
+
/*
* Pretend the requested density is actually the display density. If
* the drawable returned is not the requested density, then force it
@@ -870,7 +887,7 @@
}
}
- return loadDrawable(value, id, theme);
+ return loadDrawable(value, id, theme, useCache);
} finally {
releaseTempTypedValue(value);
}
@@ -1931,8 +1948,10 @@
mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
final int configChanges = calcConfigChanges(config);
+
LocaleList locales = mConfiguration.getLocales();
- if (locales.isEmpty()) {
+ final boolean setLocalesToDefault = locales.isEmpty();
+ if (setLocalesToDefault) {
locales = LocaleList.getDefault();
mConfiguration.setLocales(locales);
}
@@ -1961,9 +1980,26 @@
keyboardHidden = mConfiguration.keyboardHidden;
}
- // TODO: Pass the whole locale list to setConfiguration()
+ if (setLocalesToDefault || mResolvedLocale == null
+ || (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) {
+ if (locales.size() == 1) {
+ // This is an optimization to avoid the JNI call(s) when the result of
+ // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
+ mResolvedLocale = locales.getPrimary();
+ } else {
+ String[] supportedLocales = mAssets.getNonSystemLocales();
+ if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
+ // We fallback to all locales (including system locales) if there was no
+ // locale specifically supported by the assets. This is to properly support
+ // apps that only rely on the shared system assets and don't need assets of
+ // their own.
+ supportedLocales = mAssets.getLocales();
+ }
+ mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
+ }
+ }
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- adjustLanguageTag(locales.getPrimary().toLanguageTag()),
+ adjustLanguageTag(mResolvedLocale.toLanguageTag()),
mConfiguration.orientation,
mConfiguration.touchscreen,
mConfiguration.densityDpi, mConfiguration.keyboard,
@@ -1988,7 +2024,7 @@
}
synchronized (sSync) {
if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
+ mPluralRule = PluralRules.forLocale(mResolvedLocale);
}
}
}
@@ -2335,16 +2371,17 @@
* tools.
*/
public final void flushLayoutCache() {
- synchronized (mCachedXmlBlockIds) {
- // First see if this block is in our cache.
- final int num = mCachedXmlBlockIds.length;
- for (int i=0; i<num; i++) {
- mCachedXmlBlockIds[i] = -0;
- XmlBlock oldBlock = mCachedXmlBlocks[i];
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ synchronized (cachedXmlBlockFiles) {
+ final int num = cachedXmlBlockFiles.length;
+ for (int i = 0; i < num; i++) {
+ final XmlBlock oldBlock = cachedXmlBlocks[i];
if (oldBlock != null) {
oldBlock.close();
}
- mCachedXmlBlocks[i] = null;
+ cachedXmlBlockFiles[i] = null;
+ cachedXmlBlocks[i] = null;
}
}
}
@@ -2421,6 +2458,12 @@
@Nullable
Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
+ return loadDrawable(value, id, theme, true);
+ }
+
+ @Nullable
+ Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
+ throws NotFoundException {
try {
if (TRACE_FOR_PRELOAD) {
// Log only framework resources
@@ -2447,16 +2490,17 @@
}
// First, check whether we have a cached version of this drawable
- // that was inflated against the specified theme.
- if (!mPreloading) {
+ // that was inflated against the specified theme. Skip the cache if
+ // we're currently preloading or we're not using the cache.
+ if (!mPreloading && useCache) {
final Drawable cachedDrawable = caches.getInstance(key, theme);
if (cachedDrawable != null) {
return cachedDrawable;
}
}
- // Next, check preloaded drawables. These may contain unresolved theme
- // attributes.
+ // Next, check preloaded drawables. Preloaded drawables may contain
+ // unresolved theme attributes.
final ConstantState cs;
if (isColorDrawable) {
cs = sPreloadedColorDrawables.get(key);
@@ -2484,8 +2528,9 @@
}
// If we were able to obtain a drawable, store it in the appropriate
- // cache: preload, not themed, null theme, or theme-specific.
- if (dr != null) {
+ // cache: preload, not themed, null theme, or theme-specific. Don't
+ // pollute the cache with drawables loaded from a foreign density.
+ if (dr != null && useCache) {
dr.setChangingConfigurations(value.changingConfigurations);
cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
}
@@ -2714,7 +2759,16 @@
return csl;
}
- /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type)
+ /**
+ * Loads an XML parser for the specified file.
+ *
+ * @param id the resource identifier for the file
+ * @param type the type of resource (used for logging)
+ * @return a parser for the specified XML file
+ * @throws NotFoundException if the file could not be loaded
+ */
+ @NonNull
+ XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
throws NotFoundException {
final TypedValue value = obtainTempTypedValue(id);
try {
@@ -2728,53 +2782,58 @@
releaseTempTypedValue(value);
}
}
-
- /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id,
- int assetCookie, String type) throws NotFoundException {
+
+ /**
+ * Loads an XML parser for the specified file.
+ *
+ * @param file the path for the XML file to parse
+ * @param id the resource identifier for the file
+ * @param assetCookie the asset cookie for the file
+ * @param type the type of resource (used for logging)
+ * @return a parser for the specified XML file
+ * @throws NotFoundException if the file could not be loaded
+ */
+ @NonNull
+ XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
+ int assetCookie, @NonNull String type) throws NotFoundException {
if (id != 0) {
try {
- // These may be compiled...
- synchronized (mCachedXmlBlockIds) {
+ final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+ final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+ synchronized (cachedXmlBlockFiles) {
// First see if this block is in our cache.
- final int num = mCachedXmlBlockIds.length;
- for (int i=0; i<num; i++) {
- if (mCachedXmlBlockIds[i] == id) {
- //System.out.println("**** REUSING XML BLOCK! id="
- // + id + ", index=" + i);
- return mCachedXmlBlocks[i].newParser();
+ final int num = cachedXmlBlockFiles.length;
+ for (int i = 0; i < num; i++) {
+ if (cachedXmlBlockFiles[i] != null
+ && cachedXmlBlockFiles[i].equals(file)) {
+ return cachedXmlBlocks[i].newParser();
}
}
// Not in the cache, create a new block and put it at
// the next slot in the cache.
- XmlBlock block = mAssets.openXmlBlockAsset(
- assetCookie, file);
+ final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
if (block != null) {
- int pos = mLastCachedXmlBlockIndex+1;
- if (pos >= num) pos = 0;
+ final int pos = (mLastCachedXmlBlockIndex + 1) % num;
mLastCachedXmlBlockIndex = pos;
- XmlBlock oldBlock = mCachedXmlBlocks[pos];
+ final XmlBlock oldBlock = cachedXmlBlocks[pos];
if (oldBlock != null) {
oldBlock.close();
}
- mCachedXmlBlockIds[pos] = id;
- mCachedXmlBlocks[pos] = block;
- //System.out.println("**** CACHING NEW XML BLOCK! id="
- // + id + ", index=" + pos);
+ cachedXmlBlockFiles[pos] = file;
+ cachedXmlBlocks[pos] = block;
return block.newParser();
}
}
} catch (Exception e) {
- NotFoundException rnf = new NotFoundException(
- "File " + file + " from xml type " + type + " resource ID #0x"
- + Integer.toHexString(id));
+ final NotFoundException rnf = new NotFoundException("File " + file
+ + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
rnf.initCause(e);
throw rnf;
}
}
- throw new NotFoundException(
- "File " + file + " from xml type " + type + " resource ID #0x"
+ throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
+ Integer.toHexString(id));
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 433d5d1c..50e7356 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -16,6 +16,8 @@
package android.database.sqlite;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.DatabaseErrorHandler;
@@ -1683,6 +1685,21 @@
}
/**
+ * Verifies that a SQL SELECT statement is valid by compiling it.
+ * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
+ *
+ * @param sql SQL to be validated
+ * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @throws SQLiteException if {@code sql} is invalid
+ */
+ public void validateSql(@NonNull String sql, @Nullable CancellationSignal cancellationSignal) {
+ getThreadSession().prepare(sql,
+ getThreadDefaultConnectionFlags(/* readOnly =*/ true), cancellationSignal, null);
+ }
+
+ /**
* Returns true if the database is opened as read only.
*
* @return True if database is opened as read only.
diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
index 91884ab..56cba79 100644
--- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java
+++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java
@@ -386,8 +386,7 @@
// in both the wrapped and original forms.
String sqlForValidation = buildQuery(projectionIn, "(" + selection + ")", groupBy,
having, sortOrder, limit);
- validateQuerySql(db, sqlForValidation,
- cancellationSignal); // will throw if query is invalid
+ db.validateSql(sqlForValidation, cancellationSignal); // will throw if query is invalid
}
String sql = buildQuery(
@@ -404,16 +403,6 @@
}
/**
- * Verifies that a SQL SELECT statement is valid by compiling it.
- * If the SQL statement is not valid, this method will throw a {@link SQLiteException}.
- */
- private void validateQuerySql(SQLiteDatabase db, String sql,
- CancellationSignal cancellationSignal) {
- db.getThreadSession().prepare(sql,
- db.getThreadDefaultConnectionFlags(true /*readOnly*/), cancellationSignal, null);
- }
-
- /**
* Construct a SELECT statement suitable for use in a group of
* SELECT statements that will be joined through UNION operators
* in buildUnionQuery.
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index ff33bd9..b8f464d 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -73,4 +73,6 @@
void setPointerIconShape(int shapeId);
void setCustomPointerIcon(in PointerIcon icon);
+
+ void setPointerIconDetached(boolean detached);
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index fab4718..16b8722 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -829,6 +829,24 @@
}
}
+ /**
+ * Update the pointer icon status. When detached, the pointer icon disappears, and further
+ * mouse location will be stuck at the current point. Mouse movement events will still arrive,
+ * and movement should be handled through {@link MotionEvent.AXIS_RELATIVE_X} and
+ * {@link MotionEvent.AXIS_RELATIVE_Y}.
+ *
+ * @param detached true if the icon will be detached from the actual mouse movement.
+ *
+ * @hide
+ */
+ public void setPointerIconDetached(boolean detached) {
+ try {
+ mIm.setPointerIconDetached(detached);
+ } catch (RemoteException ex) {
+ // Do nothing.
+ }
+ }
+
private void populateInputDevicesLocked() {
if (mInputDevicesChangedListener == null) {
final InputDevicesChangedListener listener = new InputDevicesChangedListener();
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 8ab8991..f642f08 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -19,16 +19,22 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import android.annotation.CallSuper;
import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.MainThread;
import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.Region;
+import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.os.SystemClock;
@@ -68,6 +74,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* InputMethodService provides a standard implementation of an InputMethod,
@@ -634,6 +642,97 @@
}
/**
+ * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}.
+ *
+ * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API.
+ * Basically this functionality still needs to be considered as implementation details.</p>
+ */
+ @MainThread
+ private static final class SettingsObserver extends ContentObserver {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ ShowImeWithHardKeyboardType.UNKNOWN,
+ ShowImeWithHardKeyboardType.FALSE,
+ ShowImeWithHardKeyboardType.TRUE,
+ })
+ private @interface ShowImeWithHardKeyboardType {
+ int UNKNOWN = 0;
+ int FALSE = 1;
+ int TRUE = 2;
+ }
+ @ShowImeWithHardKeyboardType
+ private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN;
+
+ private final InputMethodService mService;
+
+ private SettingsObserver(InputMethodService service) {
+ super(new Handler(service.getMainLooper()));
+ mService = service;
+ }
+
+ /**
+ * A factory method that internally enforces two-phase initialization to make sure that the
+ * object reference will not be escaped until the object is properly constructed.
+ *
+ * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence
+ * this enforcement of two-phase initialization may be unnecessary at the moment.</p>
+ *
+ * @param service {@link InputMethodService} that needs to receive the callback.
+ * @return {@link SettingsObserver} that is already registered to
+ * {@link android.content.ContentResolver}. The caller must call
+ * {@link SettingsObserver#unregister()}.
+ */
+ public static SettingsObserver createAndRegister(InputMethodService service) {
+ final SettingsObserver observer = new SettingsObserver(service);
+ // The observer is properly constructed. Let's start accepting the event.
+ service.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD),
+ false, observer);
+ return observer;
+ }
+
+ void unregister() {
+ mService.getContentResolver().unregisterContentObserver(this);
+ }
+
+ private boolean shouldShowImeWithHardKeyboard() {
+ // Lazily initialize as needed.
+ if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) {
+ mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
+ ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
+ }
+ switch (mShowImeWithHardKeyboard) {
+ case ShowImeWithHardKeyboardType.TRUE:
+ return true;
+ case ShowImeWithHardKeyboardType.FALSE:
+ return false;
+ default:
+ Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard);
+ return false;
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final Uri showImeWithHardKeyboardUri =
+ Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+ if (showImeWithHardKeyboardUri.equals(uri)) {
+ mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(),
+ Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ?
+ ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE;
+ mService.updateInputViewShown();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}";
+ }
+ }
+ private SettingsObserver mSettingsObserver;
+
+ /**
* You can call this to customize the theme used by your IME's window.
* This theme should typically be one that derives from
* {@link android.R.style#Theme_InputMethod}, which is the default theme
@@ -682,6 +781,7 @@
super.setTheme(mTheme);
super.onCreate();
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
+ mSettingsObserver = SettingsObserver.createAndRegister(this);
// If the previous IME has occupied non-empty inset in the screen, we need to decide whether
// we continue to use the same size of the inset or update it
mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
@@ -764,6 +864,10 @@
mWindow.getWindow().setWindowAnimations(0);
mWindow.dismiss();
}
+ if (mSettingsObserver != null) {
+ mSettingsObserver.unregister();
+ mSettingsObserver = null;
+ }
}
/**
@@ -1140,21 +1244,28 @@
public boolean isInputViewShown() {
return mIsInputViewShown && mWindowVisible;
}
-
+
/**
- * Override this to control when the soft input area should be shown to
- * the user. The default implementation only shows the input view when
- * there is no hard keyboard or the keyboard is hidden. If you change what
- * this returns, you will need to call {@link #updateInputViewShown()}
- * yourself whenever the returned value may have changed to have it
- * re-evaluated and applied.
+ * Override this to control when the soft input area should be shown to the user. The default
+ * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden
+ * unless the user shows an intention to use software keyboard. If you change what this
+ * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned
+ * value may have changed to have it re-evaluated and applied.
+ *
+ * <p>When you override this method, it is recommended to call
+ * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is
+ * returned.</p>
*/
+ @CallSuper
public boolean onEvaluateInputViewShown() {
+ if (mSettingsObserver.shouldShowImeWithHardKeyboard()) {
+ return true;
+ }
Configuration config = getResources().getConfiguration();
return config.keyboard == Configuration.KEYBOARD_NOKEYS
|| config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
}
-
+
/**
* Controls the visibility of the candidates display area. By default
* it is hidden.
@@ -2483,5 +2594,6 @@
+ " touchableInsets=" + mTmpInsets.touchableInsets
+ " touchableRegion=" + mTmpInsets.touchableRegion);
p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme);
+ p.println(" mSettingsObserver=" + mSettingsObserver);
}
}
diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index ec76b8a..a66ea49 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -33,6 +33,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -90,13 +91,18 @@
* @return the list of scorers, or the empty list if there are no valid scorers.
*/
public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) {
- List<NetworkScorerAppData> scorers = new ArrayList<>();
+ // Network scorer apps can only run as the primary user so exit early if we're not the
+ // primary user.
+ if (UserHandle.getCallingUserId() != 0 /*USER_SYSTEM*/) {
+ return Collections.emptyList();
+ }
+ List<NetworkScorerAppData> scorers = new ArrayList<>();
PackageManager pm = context.getPackageManager();
// Only apps installed under the primary user of the device can be scorers.
// TODO: http://b/23422763
List<ResolveInfo> receivers =
- pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
+ pm.queryBroadcastReceiversAsUser(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
for (ResolveInfo receiver : receivers) {
// This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo
final ActivityInfo receiverInfo = receiver.activityInfo;
@@ -105,8 +111,9 @@
continue;
}
if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) {
- // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means
- // anyone could trigger network scoring and flood the framework with score requests.
+ // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which
+ // means anyone could trigger network scoring and flood the framework with score
+ // requests.
continue;
}
if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) !=
@@ -128,8 +135,8 @@
}
}
- // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app
- // label if none is present.
+ // NOTE: loadLabel will attempt to load the receiver's label and fall back to the
+ // app label if none is present.
scorers.add(new NetworkScorerAppData(receiverInfo.packageName,
receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm),
configurationActivityClassName));
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d619c0a..c7d4c65 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -371,40 +371,44 @@
flags = state.flags;
activity = state.activity;
}
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ // Make callbacks without lock
+ if (ndefCallback != null) {
+ message = ndefCallback.createNdefMessage(event);
+ }
+ if (urisCallback != null) {
+ uris = urisCallback.createBeamUris(event);
+ if (uris != null) {
+ ArrayList<Uri> validUris = new ArrayList<Uri>();
+ for (Uri uri : uris) {
+ if (uri == null) {
+ Log.e(TAG, "Uri not allowed to be null.");
+ continue;
+ }
+ String scheme = uri.getScheme();
+ if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
+ !scheme.equalsIgnoreCase("content"))) {
+ Log.e(TAG, "Uri needs to have " +
+ "either scheme file or scheme content");
+ continue;
+ }
+ uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
+ validUris.add(uri);
+ }
- // Make callbacks without lock
- if (ndefCallback != null) {
- message = ndefCallback.createNdefMessage(event);
- }
- if (urisCallback != null) {
- uris = urisCallback.createBeamUris(event);
- if (uris != null) {
- ArrayList<Uri> validUris = new ArrayList<Uri>();
- for (Uri uri : uris) {
- if (uri == null) {
- Log.e(TAG, "Uri not allowed to be null.");
- continue;
- }
- String scheme = uri.getScheme();
- if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
- !scheme.equalsIgnoreCase("content"))) {
- Log.e(TAG, "Uri needs to have " +
- "either scheme file or scheme content");
- continue;
- }
- uri = ContentProvider.maybeAddUserId(uri, UserHandle.myUserId());
- validUris.add(uri);
+ uris = validUris.toArray(new Uri[validUris.size()]);
}
-
- uris = validUris.toArray(new Uri[validUris.size()]);
}
- }
- if (uris != null && uris.length > 0) {
- for (Uri uri : uris) {
- // Grant the NFC process permission to read these URIs
- activity.grantUriPermission("com.android.nfc", uri,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ if (uris != null && uris.length > 0) {
+ for (Uri uri : uris) {
+ // Grant the NFC process permission to read these URIs
+ activity.grantUriPermission("com.android.nfc", uri,
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return new BeamShareData(message, uris, new UserHandle(UserHandle.myUserId()), flags);
}
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index cd483b1..ee7bd9a 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -32,7 +32,9 @@
private static final String TAG = "Bundle";
static final boolean DEBUG = false;
+ // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+
static final Parcel EMPTY_PARCEL;
static {
@@ -1308,6 +1310,8 @@
* @param parcel The parcel to copy this bundle to.
*/
void writeToParcelInner(Parcel parcel, int flags) {
+ // Keep implementation in sync with writeToParcel() in
+ // frameworks/native/libs/binder/PersistableBundle.cpp.
if (mParcelledData != null) {
if (mParcelledData == EMPTY_PARCEL) {
parcel.writeInt(0);
@@ -1345,6 +1349,8 @@
* @param parcel The parcel to overwrite this bundle from.
*/
void readFromParcelInner(Parcel parcel) {
+ // Keep implementation in sync with readFromParcel() in
+ // frameworks/native/libs/binder/PersistableBundle.cpp.
int length = parcel.readInt();
readFromParcelInner(parcel, length);
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index a01d34a..2ca9ab8a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -37,6 +37,7 @@
private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
+ private static final String ENV_ODM_ROOT = "ODM_ROOT";
private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
/** {@hide} */
@@ -56,6 +57,7 @@
private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
+ private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
private static UserEnvironment sCurrentUser;
@@ -156,6 +158,16 @@
}
/**
+ * Return root directory of the "odm" partition holding ODM customizations,
+ * if any. If present, the partition is mounted read-only.
+ *
+ * @hide
+ */
+ public static File getOdmDirectory() {
+ return DIR_ODM_ROOT;
+ }
+
+ /**
* Return root directory of the "vendor" partition that holds vendor-provided
* software that should persist across simple reflashing of the "system" partition.
* @hide
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 9b68f90..2631247 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -204,6 +204,7 @@
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
+ // Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
private static final int VAL_NULL = -1;
private static final int VAL_STRING = 0;
private static final int VAL_INTEGER = 1;
@@ -704,6 +705,8 @@
writeInt(-1);
return;
}
+ // Keep the format of this Parcel in sync with writeToParcelInner() in
+ // frameworks/native/libs/binder/PersistableBundle.cpp.
final int N = val.size();
writeInt(N);
if (DEBUG_ARRAY_MAP) {
@@ -1370,7 +1373,13 @@
// Must be before Parcelable
writeInt(VAL_BUNDLE);
writeBundle((Bundle) v);
+ } else if (v instanceof PersistableBundle) {
+ writeInt(VAL_PERSISTABLEBUNDLE);
+ writePersistableBundle((PersistableBundle) v);
} else if (v instanceof Parcelable) {
+ // IMPOTANT: cases for classes that implement Parcelable must
+ // come before the Parcelable case, so that their specific VAL_*
+ // types will be written.
writeInt(VAL_PARCELABLE);
writeParcelable((Parcelable) v, 0);
} else if (v instanceof Short) {
@@ -1426,9 +1435,6 @@
} else if (v instanceof Byte) {
writeInt(VAL_BYTE);
writeInt((Byte) v);
- } else if (v instanceof PersistableBundle) {
- writeInt(VAL_PERSISTABLEBUNDLE);
- writePersistableBundle((PersistableBundle) v);
} else if (v instanceof Size) {
writeInt(VAL_SIZE);
writeSize((Size) v);
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 135f369..d5491d3 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -233,6 +233,19 @@
final FileDescriptor fd = openInternal(file, mode);
if (fd == null) return null;
+ return fromFd(fd, handler, listener);
+ }
+
+ /** {@hide} */
+ public static ParcelFileDescriptor fromFd(
+ FileDescriptor fd, Handler handler, final OnCloseListener listener) throws IOException {
+ if (handler == null) {
+ throw new IllegalArgumentException("Handler must not be null");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null");
+ }
+
final FileDescriptor[] comm = createCommSocketPair();
final ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd, comm[0]);
final MessageQueue queue = handler.getLooper().getQueue();
diff --git a/core/java/android/os/PersistableBundle.aidl b/core/java/android/os/PersistableBundle.aidl
index 5b05873..94e8607 100644
--- a/core/java/android/os/PersistableBundle.aidl
+++ b/core/java/android/os/PersistableBundle.aidl
@@ -2,19 +2,19 @@
**
** Copyright 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
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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;
-parcelable PersistableBundle;
+parcelable PersistableBundle cpp_header "binder/PersistableBundle.h";
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 120654f..4159d89 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -389,6 +389,13 @@
public static final String REBOOT_RECOVERY = "recovery";
/**
+ * The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
+ * the device.
+ * @hide
+ */
+ public static final String REBOOT_REQUESTED_BY_DEVICE_OWNER = "deviceowner";
+
+ /**
* The value to pass as the 'reason' argument to android_reboot().
* @hide
*/
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 13b8b66..2ba4aa4 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -112,8 +112,10 @@
/**
* Return a list of all currently running services.
+ * @return an array of all currently running services, or <code>null</code> in
+ * case of an exception
*/
- public static String[] listServices() throws RemoteException {
+ public static String[] listServices() {
try {
return getIServiceManager().listServices();
} catch (RemoteException e) {
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index f946ca7..867d0b9 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -16,7 +16,10 @@
package android.os;
+import android.annotation.AppIdInt;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+import android.annotation.UserIdInt;
import java.io.PrintWriter;
@@ -127,7 +130,7 @@
* Returns the user id for a given uid.
* @hide
*/
- public static int getUserId(int uid) {
+ public static @UserIdInt int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
} else {
@@ -136,12 +139,12 @@
}
/** @hide */
- public static int getCallingUserId() {
+ public static @UserIdInt int getCallingUserId() {
return getUserId(Binder.getCallingUid());
}
/** @hide */
- public static UserHandle of(int userId) {
+ public static UserHandle of(@UserIdInt int userId) {
return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
}
@@ -149,7 +152,7 @@
* Returns the uid that is composed from the userId and the appId.
* @hide
*/
- public static int getUid(int userId, int appId) {
+ public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
if (MU_ENABLED) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
} else {
@@ -161,7 +164,8 @@
* Returns the app id (or base uid) for a given uid, stripping out the user id from it.
* @hide
*/
- public static int getAppId(int uid) {
+ @TestApi
+ public static @AppIdInt int getAppId(int uid) {
return uid % PER_USER_RANGE;
}
@@ -169,7 +173,7 @@
* Returns the gid shared between all apps with this userId.
* @hide
*/
- public static int getUserGid(int userId) {
+ public static int getUserGid(@UserIdInt int userId) {
return getUid(userId, Process.SHARED_USER_GID);
}
@@ -186,7 +190,7 @@
* Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
* @hide
*/
- public static int getAppIdFromSharedAppGid(int gid) {
+ public static @AppIdInt int getAppIdFromSharedAppGid(int gid) {
final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
- Process.FIRST_SHARED_APPLICATION_GID;
if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) {
@@ -257,7 +261,7 @@
}
/** @hide */
- public static int parseUserArg(String arg) {
+ public static @UserIdInt int parseUserArg(String arg) {
int userId;
if ("all".equals(arg)) {
userId = UserHandle.USER_ALL;
@@ -279,7 +283,7 @@
* @hide
*/
@SystemApi
- public static int myUserId() {
+ public static @UserIdInt int myUserId() {
return getUserId(Process.myUid());
}
@@ -315,7 +319,7 @@
* @hide
*/
@SystemApi
- public int getIdentifier() {
+ public @UserIdInt int getIdentifier() {
return mHandle;
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1f16c4a..887dd17 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
@@ -31,6 +32,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.storage.StorageManager;
import android.provider.Settings;
import android.util.Log;
import android.view.WindowManager.LayoutParams;
@@ -56,6 +58,10 @@
* Authenticator.
* The default value is <code>false</code>.
*
+ * <p>From {@link android.os.Build.VERSION_CODES#N} a profile or device owner app can still
+ * use {@link android.accounts.AccountManager} APIs to add or remove accounts when account
+ * management is disallowed.
+ *
* <p/>Key for user restrictions.
* <p/>Type: Boolean
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
@@ -596,7 +602,7 @@
* @return the user handle of this process.
* @hide
*/
- public int getUserHandle() {
+ public @UserIdInt int getUserHandle() {
return UserHandle.myUserId();
}
@@ -666,7 +672,7 @@
* Returns whether the provided user is an admin user. There can be more than one admin
* user.
*/
- public boolean isUserAdmin(int userId) {
+ public boolean isUserAdmin(@UserIdInt int userId) {
UserInfo user = getUserInfo(userId);
return user != null && user.isAdmin();
}
@@ -690,7 +696,7 @@
* Checks if specified user can have restricted profile.
* @hide
*/
- public boolean canHaveRestrictedProfile(int userId) {
+ public boolean canHaveRestrictedProfile(@UserIdInt int userId) {
try {
return mService.canHaveRestrictedProfile(userId);
} catch (RemoteException re) {
@@ -736,7 +742,7 @@
* Returns whether the specified user is ephemeral.
* @hide
*/
- public boolean isUserEphemeral(int userId) {
+ public boolean isUserEphemeral(@UserIdInt int userId) {
final UserInfo user = getUserInfo(userId);
return user != null && user.isEphemeral();
}
@@ -852,12 +858,15 @@
* @param user to retrieve the unlocked state for.
*/
public boolean isUserUnlocked(UserHandle user) {
- try {
- return ActivityManagerNative.getDefault().isUserRunning(
- user.getIdentifier(), ActivityManager.FLAG_AND_UNLOCKED);
- } catch (RemoteException e) {
- return false;
- }
+ return isUserUnlocked(user.getIdentifier());
+ }
+
+ /** {@hide} */
+ public boolean isUserUnlocked(@UserIdInt int userId) {
+ // TODO: eventually pivot this back to look at ActivityManager state,
+ // but there is race where we can start a non-encryption-aware launcher
+ // before that lifecycle has entered the running unlocked state.
+ return mContext.getSystemService(StorageManager.class).isUserKeyUnlocked(userId);
}
/**
@@ -867,7 +876,7 @@
* @return the UserInfo object for a specific user.
* @hide
*/
- public UserInfo getUserInfo(int userHandle) {
+ public UserInfo getUserInfo(@UserIdInt int userHandle) {
try {
return mService.getUserInfo(userHandle);
} catch (RemoteException re) {
@@ -1085,7 +1094,7 @@
* @return the UserInfo object for the created user, or null if the user could not be created.
* @hide
*/
- public UserInfo createProfileForUser(String name, int flags, int userHandle) {
+ public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
try {
return mService.createProfileForUser(name, flags, userHandle);
} catch (RemoteException re) {
@@ -1125,7 +1134,7 @@
* @param userHandle
* @return
*/
- public boolean markGuestForDeletion(int userHandle) {
+ public boolean markGuestForDeletion(@UserIdInt int userHandle) {
try {
return mService.markGuestForDeletion(userHandle);
} catch (RemoteException re) {
@@ -1142,7 +1151,7 @@
* @param userHandle the id of the profile to enable
* @hide
*/
- public void setUserEnabled(int userHandle) {
+ public void setUserEnabled(@UserIdInt int userHandle) {
try {
mService.setUserEnabled(userHandle);
} catch (RemoteException e) {
@@ -1181,7 +1190,7 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Manifest.permission.MANAGE_USERS
})
- public @Nullable String getUserAccount(int userHandle) {
+ public @Nullable String getUserAccount(@UserIdInt int userHandle) {
try {
return mService.getUserAccount(userHandle);
} catch (RemoteException re) {
@@ -1198,7 +1207,7 @@
Manifest.permission.INTERACT_ACROSS_USERS_FULL,
Manifest.permission.MANAGE_USERS
})
- public void setUserAccount(int userHandle, @Nullable String accountName) {
+ public void setUserAccount(@UserIdInt int userHandle, @Nullable String accountName) {
try {
mService.setUserAccount(userHandle, accountName);
} catch (RemoteException re) {
@@ -1251,7 +1260,7 @@
* @return true if more managed profiles can be added, false if limit has been reached.
* @hide
*/
- public boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne) {
+ public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) {
try {
return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne);
} catch (RemoteException re) {
@@ -1271,7 +1280,7 @@
* @return the list of profiles.
* @hide
*/
- public List<UserInfo> getProfiles(int userHandle) {
+ public List<UserInfo> getProfiles(@UserIdInt int userHandle) {
try {
return mService.getProfiles(userHandle, false /* enabledOnly */);
} catch (RemoteException re) {
@@ -1287,7 +1296,7 @@
* @return true if the two user ids are in the same profile group.
* @hide
*/
- public boolean isSameProfileGroup(int userId, int otherUserId) {
+ public boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) {
try {
return mService.isSameProfileGroup(userId, otherUserId);
} catch (RemoteException re) {
@@ -1306,7 +1315,7 @@
* @return the list of profiles.
* @hide
*/
- public List<UserInfo> getEnabledProfiles(int userHandle) {
+ public List<UserInfo> getEnabledProfiles(@UserIdInt int userHandle) {
try {
return mService.getProfiles(userHandle, true /* enabledOnly */);
} catch (RemoteException re) {
@@ -1344,7 +1353,7 @@
*
* @hide
*/
- public int getCredentialOwnerProfile(int userHandle) {
+ public int getCredentialOwnerProfile(@UserIdInt int userHandle) {
try {
return mService.getCredentialOwnerProfile(userHandle);
} catch (RemoteException re) {
@@ -1359,7 +1368,7 @@
*
* @hide
*/
- public UserInfo getProfileParent(int userHandle) {
+ public UserInfo getProfileParent(@UserIdInt int userHandle) {
try {
return mService.getProfileParent(userHandle);
} catch (RemoteException re) {
@@ -1375,7 +1384,7 @@
* @param enableQuietMode Whether quiet mode should be enabled or disabled.
* @hide
*/
- public void setQuietModeEnabled(int userHandle, boolean enableQuietMode) {
+ public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
try {
mService.setQuietModeEnabled(userHandle, enableQuietMode);
} catch (RemoteException e) {
@@ -1491,7 +1500,7 @@
* @param userHandle the integer handle of the user, where 0 is the primary user.
* @hide
*/
- public boolean removeUser(int userHandle) {
+ public boolean removeUser(@UserIdInt int userHandle) {
try {
return mService.removeUser(userHandle);
} catch (RemoteException re) {
@@ -1508,7 +1517,7 @@
* @param name the new name for the user
* @hide
*/
- public void setUserName(int userHandle, String name) {
+ public void setUserName(@UserIdInt int userHandle, String name) {
try {
mService.setUserName(userHandle, name);
} catch (RemoteException re) {
@@ -1522,7 +1531,7 @@
* @param icon the bitmap to set as the photo.
* @hide
*/
- public void setUserIcon(int userHandle, Bitmap icon) {
+ public void setUserIcon(@UserIdInt int userHandle, Bitmap icon) {
try {
mService.setUserIcon(userHandle, icon);
} catch (RemoteException re) {
@@ -1537,7 +1546,7 @@
* @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default.
* @hide
*/
- public Bitmap getUserIcon(int userHandle) {
+ public Bitmap getUserIcon(@UserIdInt int userHandle) {
try {
ParcelFileDescriptor fd = mService.getUserIcon(userHandle);
if (fd != null) {
@@ -1603,7 +1612,7 @@
* @return a serial number associated with that user, or -1 if the userHandle is not valid.
* @hide
*/
- public int getUserSerialNumber(int userHandle) {
+ public int getUserSerialNumber(@UserIdInt int userHandle) {
try {
return mService.getUserSerialNumber(userHandle);
} catch (RemoteException re) {
@@ -1621,7 +1630,7 @@
* is not valid.
* @hide
*/
- public int getUserHandle(int userSerialNumber) {
+ public @UserIdInt int getUserHandle(int userSerialNumber) {
try {
return mService.getUserHandle(userSerialNumber);
} catch (RemoteException re) {
@@ -1631,12 +1640,23 @@
}
/**
- * Returns a Bundle containing any saved application restrictions for this user, for the
+ * Returns a {@code Bundle} containing any saved application restrictions for this user, for the
* given package name. Only an application with this package name can call this method.
+ *
+ * <p>The returned {@link Bundle} consists of key-value pairs, as defined by the application,
+ * where the types of values may be:
+ * <ul>
+ * <li>{@code boolean}
+ * <li>{@code int}
+ * <li>{@code String} or {@code String[]}
+ * <li>From {@link android.os.Build.VERSION_CODES#M}, {@code Bundle} or {@code Bundle[]}
+ * </ul>
+ *
* @param packageName the package name of the calling application
- * @return a Bundle with the restrictions as key/value pairs, or null if there are no
- * saved restrictions. The values can be of type Boolean, String or String[], depending
- * on the restriction type, as defined by the application.
+ * @return a {@code Bundle} with the restrictions for that package, or {@code null} if there
+ * are no saved restrictions.
+ *
+ * @see #KEY_RESTRICTIONS_PENDING
*/
public Bundle getApplicationRestrictions(String packageName) {
try {
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 8fa7ab9..9a80e37 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,6 +16,7 @@
package android.print;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
@@ -53,6 +54,19 @@
void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
void validatePrinters(in List<PrinterId> printerIds, int userId);
void startPrinterStateTracking(in PrinterId printerId, int userId);
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @param userId the id of the user requesting the printer
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ Icon getCustomPrinterIcon(in PrinterId printerId, int userId);
+
void stopPrinterStateTracking(in PrinterId printerId, int userId);
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
int userId);
diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl
index b7cfbea..469a4ea 100644
--- a/core/java/android/print/IPrintSpooler.aidl
+++ b/core/java/android/print/IPrintSpooler.aidl
@@ -17,9 +17,11 @@
package android.print;
import android.content.ComponentName;
+import android.graphics.drawable.Icon;
import android.os.ParcelFileDescriptor;
import android.print.IPrintSpoolerClient;
import android.print.IPrintSpoolerCallbacks;
+import android.print.PrinterId;
import android.print.PrinterInfo;
import android.print.PrintAttributes;
import android.print.PrintJobId;
@@ -58,10 +60,49 @@
*/
void setStatus(in PrintJobId printJobId, in CharSequence status);
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @param callbacks the callback to call once icon is stored in case
+ * @param sequence the sequence number of the call
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon,
+ in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @param callbacks the callback to call once icon is retrieved
+ * @param sequence the sequence number of the call
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void getCustomPrinterIcon(in PrinterId printerId,
+ in IPrintSpoolerCallbacks callbacks, in int sequence);
+
+ /**
+ * Clear all state from the custom printer icon cache.
+ *
+ * @param callbacks the callback to call once cache is cleared
+ * @param sequence the sequence number of the call
+ */
+ void clearCustomPrinterIconCache(in IPrintSpoolerCallbacks callbacks,
+ in int sequence);
+
void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId);
void setClient(IPrintSpoolerClient client);
void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling);
- void removeApprovedPrintService(in ComponentName serviceToRemove);
+
+ /**
+ * Remove all approved print services that are not in the given set.
+ *
+ * @param servicesToKeep The names of the services to keep
+ */
+ void pruneApprovedPrintServices(in List<ComponentName> servicesToKeep);
}
diff --git a/core/java/android/print/IPrintSpoolerCallbacks.aidl b/core/java/android/print/IPrintSpoolerCallbacks.aidl
index 45c5332..23d706a 100644
--- a/core/java/android/print/IPrintSpoolerCallbacks.aidl
+++ b/core/java/android/print/IPrintSpoolerCallbacks.aidl
@@ -16,7 +16,9 @@
package android.print;
+import android.graphics.drawable.Icon;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
import java.util.List;
/**
@@ -32,4 +34,27 @@
void onSetPrintJobStateResult(boolean success, int sequence);
void onSetPrintJobTagResult(boolean success, int sequence);
void onGetPrintJobInfoResult(in PrintJobInfo printJob, int sequence);
+
+ /**
+ * Deliver the result of a request of a custom printer icon.
+ *
+ * @param icon the icon that was retrieved, or null if no icon could be
+ * found
+ * @param sequence the sequence number of the call to get the icon
+ */
+ void onGetCustomPrinterIconResult(in Icon icon, int sequence);
+
+ /**
+ * Declare that the print spooler cached a custom printer icon.
+ *
+ * @param sequence the sequence number of the call to cache the icon
+ */
+ void onCustomPrinterIconCached(int sequence);
+
+ /**
+ * Declare that the custom printer icon cache was cleared.
+ *
+ * @param sequence the sequence number of the call to clear the cache
+ */
+ void customPrinterIconCacheCleared(int sequence);
}
diff --git a/core/java/android/print/PageRange.java b/core/java/android/print/PageRange.java
index 8bc157a..57c7718 100644
--- a/core/java/android/print/PageRange.java
+++ b/core/java/android/print/PageRange.java
@@ -16,6 +16,8 @@
package android.print;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -42,7 +44,7 @@
* @throws IllegalArgumentException If start is less than zero or end
* is less than zero or start greater than end.
*/
- public PageRange(int start, int end) {
+ public PageRange(@IntRange(from = 0) int start, @IntRange(from = 0) int end) {
if (start < 0) {
throw new IllegalArgumentException("start cannot be less than zero.");
}
@@ -56,7 +58,7 @@
mEnd = end;
}
- private PageRange (Parcel parcel) {
+ private PageRange(@NonNull Parcel parcel) {
this(parcel.readInt(), parcel.readInt());
}
@@ -65,7 +67,7 @@
*
* @return The start page index.
*/
- public int getStart() {
+ public @IntRange(from = 0) int getStart() {
return mStart;
}
@@ -74,7 +76,7 @@
*
* @return The end page index.
*/
- public int getEnd() {
+ public @IntRange(from = 0) int getEnd() {
return mEnd;
}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 2afbb99..8892e34 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -16,6 +16,10 @@
package android.print;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources.NotFoundException;
@@ -27,6 +31,8 @@
import com.android.internal.R;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Map;
/**
@@ -37,6 +43,13 @@
* 10 mills (thousand of an inch) on all sides, and be black and white.
*/
public final class PrintAttributes implements Parcelable {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ COLOR_MODE_MONOCHROME, COLOR_MODE_COLOR
+ })
+ public @interface ColorMode {
+ }
/** Color mode: Monochrome color scheme, for example one color is used. */
public static final int COLOR_MODE_MONOCHROME = 1 << 0;
/** Color mode: Color color scheme, for example many colors are used. */
@@ -45,6 +58,13 @@
private static final int VALID_COLOR_MODES =
COLOR_MODE_MONOCHROME | COLOR_MODE_COLOR;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, value = {
+ DUPLEX_MODE_NONE, DUPLEX_MODE_LONG_EDGE, DUPLEX_MODE_SHORT_EDGE
+ })
+ public @interface DuplexMode {
+ }
/** Duplex mode: No duplexing. */
public static final int DUPLEX_MODE_NONE = 1 << 0;
/** Duplex mode: Pages are turned sideways along the long edge - like a book. */
@@ -66,7 +86,7 @@
/* hide constructor */
}
- private PrintAttributes(Parcel parcel) {
+ private PrintAttributes(@NonNull Parcel parcel) {
mMediaSize = (parcel.readInt() == 1) ? MediaSize.createFromParcel(parcel) : null;
mResolution = (parcel.readInt() == 1) ? Resolution.createFromParcel(parcel) : null;
mMinMargins = (parcel.readInt() == 1) ? Margins.createFromParcel(parcel) : null;
@@ -79,7 +99,7 @@
*
* @return The media size or <code>null</code> if not set.
*/
- public MediaSize getMediaSize() {
+ public @Nullable MediaSize getMediaSize() {
return mMediaSize;
}
@@ -99,7 +119,7 @@
*
* @return The resolution or <code>null</code> if not set.
*/
- public Resolution getResolution() {
+ public @Nullable Resolution getResolution() {
return mResolution;
}
@@ -127,7 +147,7 @@
*
* @return The margins or <code>null</code> if not set.
*/
- public Margins getMinMargins() {
+ public @Nullable Margins getMinMargins() {
return mMinMargins;
}
@@ -158,7 +178,7 @@
* @see #COLOR_MODE_COLOR
* @see #COLOR_MODE_MONOCHROME
*/
- public int getColorMode() {
+ public @ColorMode int getColorMode() {
return mColorMode;
}
@@ -199,7 +219,7 @@
* @see #DUPLEX_MODE_LONG_EDGE
* @see #DUPLEX_MODE_SHORT_EDGE
*/
- public int getDuplexMode() {
+ public @DuplexMode int getDuplexMode() {
return mDuplexMode;
}
@@ -828,7 +848,8 @@
* or the widthMils is less than or equal to zero or the heightMils is less
* than or equal to zero.
*/
- public MediaSize(String id, String label, int widthMils, int heightMils) {
+ public MediaSize(@NonNull String id, @NonNull String label,
+ @IntRange(from = 1) int widthMils, @IntRange(from = 1) int heightMils) {
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be empty.");
}
@@ -872,7 +893,7 @@
*
* @return The unique media size id.
*/
- public String getId() {
+ public @NonNull String getId() {
return mId;
}
@@ -882,7 +903,7 @@
* @param packageManager The package manager for loading the label.
* @return The human readable label.
*/
- public String getLabel(PackageManager packageManager) {
+ public @NonNull String getLabel(@NonNull PackageManager packageManager) {
if (!TextUtils.isEmpty(mPackageName) && mLabelResId > 0) {
try {
return packageManager.getResourcesForApplication(
@@ -903,7 +924,7 @@
*
* @return The media width.
*/
- public int getWidthMils() {
+ public @IntRange(from = 1) int getWidthMils() {
return mWidthMils;
}
@@ -912,7 +933,7 @@
*
* @return The media height.
*/
- public int getHeightMils() {
+ public @IntRange(from = 1) int getHeightMils() {
return mHeightMils;
}
@@ -934,7 +955,7 @@
* @return New instance in landscape orientation if this one
* is in landscape, otherwise this instance.
*/
- public MediaSize asPortrait() {
+ public @NonNull MediaSize asPortrait() {
if (isPortrait()) {
return this;
}
@@ -951,7 +972,7 @@
* @return New instance in landscape orientation if this one
* is in portrait, otherwise this instance.
*/
- public MediaSize asLandscape() {
+ public @NonNull MediaSize asLandscape() {
if (!isPortrait()) {
return this;
}
@@ -1063,7 +1084,8 @@
* or the horizontalDpi is less than or equal to zero or the verticalDpi is
* less than or equal to zero.
*/
- public Resolution(String id, String label, int horizontalDpi, int verticalDpi) {
+ public Resolution(@NonNull String id, @NonNull String label,
+ @IntRange(from = 1) int horizontalDpi, @IntRange(from = 1) int verticalDpi) {
if (TextUtils.isEmpty(id)) {
throw new IllegalArgumentException("id cannot be empty.");
}
@@ -1094,7 +1116,7 @@
*
* @return The unique resolution id.
*/
- public String getId() {
+ public @NonNull String getId() {
return mId;
}
@@ -1103,7 +1125,7 @@
*
* @return The human readable label.
*/
- public String getLabel() {
+ public @NonNull String getLabel() {
return mLabel;
}
@@ -1112,7 +1134,7 @@
*
* @return The horizontal resolution.
*/
- public int getHorizontalDpi() {
+ public @IntRange(from = 1) int getHorizontalDpi() {
return mHorizontalDpi;
}
@@ -1121,7 +1143,7 @@
*
* @return The vertical resolution.
*/
- public int getVerticalDpi() {
+ public @IntRange(from = 1) int getVerticalDpi() {
return mVerticalDpi;
}
@@ -1204,7 +1226,8 @@
* @param rightMils The right margin in mils (thousands of an inch).
* @param bottomMils The bottom margin in mils (thousands of an inch).
*/
- public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
+ public Margins(@IntRange(from = 0) int leftMils, @IntRange(from = 0) int topMils,
+ @IntRange(from = 0) int rightMils, @IntRange(from = 0) int bottomMils) {
mTopMils = topMils;
mLeftMils = leftMils;
mRightMils = rightMils;
@@ -1216,7 +1239,7 @@
*
* @return The left margin.
*/
- public int getLeftMils() {
+ public @IntRange(from = 0) int getLeftMils() {
return mLeftMils;
}
@@ -1225,7 +1248,7 @@
*
* @return The top margin.
*/
- public int getTopMils() {
+ public @IntRange(from = 0) int getTopMils() {
return mTopMils;
}
@@ -1234,7 +1257,7 @@
*
* @return The right margin.
*/
- public int getRightMils() {
+ public @IntRange(from = 0) int getRightMils() {
return mRightMils;
}
@@ -1243,7 +1266,7 @@
*
* @return The bottom margin.
*/
- public int getBottomMils() {
+ public @IntRange(from = 0) int getBottomMils() {
return mBottomMils;
}
@@ -1368,7 +1391,7 @@
* @param mediaSize The media size.
* @return This builder.
*/
- public Builder setMediaSize(MediaSize mediaSize) {
+ public @NonNull Builder setMediaSize(@NonNull MediaSize mediaSize) {
mAttributes.setMediaSize(mediaSize);
return this;
}
@@ -1379,7 +1402,7 @@
* @param resolution The resolution.
* @return This builder.
*/
- public Builder setResolution(Resolution resolution) {
+ public @NonNull Builder setResolution(@NonNull Resolution resolution) {
mAttributes.setResolution(resolution);
return this;
}
@@ -1391,7 +1414,7 @@
* @param margins The margins.
* @return This builder.
*/
- public Builder setMinMargins(Margins margins) {
+ public @NonNull Builder setMinMargins(@NonNull Margins margins) {
mAttributes.setMinMargins(margins);
return this;
}
@@ -1405,7 +1428,7 @@
* @see PrintAttributes#COLOR_MODE_MONOCHROME
* @see PrintAttributes#COLOR_MODE_COLOR
*/
- public Builder setColorMode(int colorMode) {
+ public @NonNull Builder setColorMode(@ColorMode int colorMode) {
mAttributes.setColorMode(colorMode);
return this;
}
@@ -1420,7 +1443,7 @@
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public Builder setDuplexMode(int duplexMode) {
+ public @NonNull Builder setDuplexMode(@DuplexMode int duplexMode) {
mAttributes.setDuplexMode(duplexMode);
return this;
}
@@ -1430,7 +1453,7 @@
*
* @return The new instance.
*/
- public PrintAttributes build() {
+ public @NonNull PrintAttributes build() {
return mAttributes;
}
}
diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java
index 44e6410..db3b6f4 100644
--- a/core/java/android/print/PrintDocumentInfo.java
+++ b/core/java/android/print/PrintDocumentInfo.java
@@ -16,10 +16,16 @@
package android.print;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class encapsulates information about a document for printing
* purposes. This meta-data is used by the platform and print services,
@@ -74,6 +80,13 @@
*/
public static final int PAGE_COUNT_UNKNOWN = -1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ CONTENT_TYPE_UNKNOWN, CONTENT_TYPE_DOCUMENT, CONTENT_TYPE_PHOTO
+ })
+ public @interface ContentType {
+ }
/**
* Content type: unknown.
*/
@@ -116,9 +129,9 @@
/**
* Creates a new instance.
*
- * @param Prototype from which to clone.
+ * @param prototype from which to clone.
*/
- private PrintDocumentInfo(PrintDocumentInfo prototype) {
+ private PrintDocumentInfo(@NonNull PrintDocumentInfo prototype) {
mName = prototype.mName;
mPageCount = prototype.mPageCount;
mContentType = prototype.mContentType;
@@ -143,7 +156,7 @@
*
* @return The document name.
*/
- public String getName() {
+ public @NonNull String getName() {
return mName;
}
@@ -154,7 +167,7 @@
*
* @see #PAGE_COUNT_UNKNOWN
*/
- public int getPageCount() {
+ public @IntRange(from = -1) int getPageCount() {
return mPageCount;
}
@@ -167,7 +180,7 @@
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public int getContentType() {
+ public @ContentType int getContentType() {
return mContentType;
}
@@ -176,7 +189,7 @@
*
* @return The data size.
*/
- public long getDataSize() {
+ public @IntRange(from = 0) long getDataSize() {
return mDataSize;
}
@@ -187,7 +200,7 @@
*
* @hide
*/
- public void setDataSize(long dataSize) {
+ public void setDataSize(@IntRange(from = 0) long dataSize) {
mDataSize = dataSize;
}
@@ -288,7 +301,7 @@
* is the file name if the content it describes is saved as a PDF.
* Cannot be empty.
*/
- public Builder(String name) {
+ public Builder(@NonNull String name) {
if (TextUtils.isEmpty(name)) {
throw new IllegalArgumentException("name cannot be empty");
}
@@ -302,10 +315,11 @@
* <strong>Default: </strong> {@link #PAGE_COUNT_UNKNOWN}
* </p>
*
- * @param pageCount The number of pages. Must be greater than
- * or equal to zero or {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+ * @param pageCount The number of pages. Must be greater than or equal to zero or
+ * {@link PrintDocumentInfo#PAGE_COUNT_UNKNOWN}.
+ * @return This builder.
*/
- public Builder setPageCount(int pageCount) {
+ public @NonNull Builder setPageCount(@IntRange(from = -1) int pageCount) {
if (pageCount < 0 && pageCount != PAGE_COUNT_UNKNOWN) {
throw new IllegalArgumentException("pageCount"
+ " must be greater than or equal to zero or"
@@ -322,12 +336,12 @@
* </p>
*
* @param type The content type.
- *
+ * @return This builder.
* @see #CONTENT_TYPE_UNKNOWN
* @see #CONTENT_TYPE_DOCUMENT
* @see #CONTENT_TYPE_PHOTO
*/
- public Builder setContentType(int type) {
+ public @NonNull Builder setContentType(@ContentType int type) {
mPrototype.mContentType = type;
return this;
}
@@ -337,7 +351,7 @@
*
* @return The new instance.
*/
- public PrintDocumentInfo build() {
+ public @NonNull PrintDocumentInfo build() {
// Zero pages is the same as unknown as in this case
// we will have to ask for all pages and look a the
// wiritten PDF file for the page count.
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 0abe2193..777baab 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -16,6 +16,9 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
/**
* This class represents a print job from the perspective of an
* application. It contains behavior methods for performing operations
@@ -41,7 +44,7 @@
*
* @return The id.
*/
- public PrintJobId getId() {
+ public @NonNull PrintJobId getId() {
return mCachedInfo.getId();
}
@@ -55,7 +58,7 @@
*
* @return The print job info.
*/
- public PrintJobInfo getInfo() {
+ public @Nullable PrintJobInfo getInfo() {
if (isInImmutableState()) {
return mCachedInfo;
}
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
index 01550e2..a2ee02b 100644
--- a/core/java/android/print/PrintJobId.java
+++ b/core/java/android/print/PrintJobId.java
@@ -16,6 +16,7 @@
package android.print;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -91,14 +92,14 @@
*
* @hide
*/
- public String flattenToString() {
+ public @NonNull String flattenToString() {
return mValue;
}
/**
* Unflattens a print job id from a string.
*
- * @string The string.
+ * @param string The string.
* @return The unflattened id, or null if the string is malformed.
*
* @hide
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 7148c87..21836b3 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -17,6 +17,9 @@
package android.print;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.os.Bundle;
@@ -25,6 +28,8 @@
import com.android.internal.util.Preconditions;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
/**
@@ -35,6 +40,15 @@
*/
public final class PrintJobInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ STATE_CREATED, STATE_QUEUED, STATE_STARTED, STATE_BLOCKED, STATE_COMPLETED,
+ STATE_FAILED, STATE_CANCELED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {
+ }
+
/**
* Constant for matching any print job state.
*
@@ -200,7 +214,7 @@
mAdvancedOptions = other.mAdvancedOptions;
}
- private PrintJobInfo(Parcel parcel) {
+ private PrintJobInfo(@NonNull Parcel parcel) {
mId = parcel.readParcelable(null);
mLabel = parcel.readString();
mPrinterId = parcel.readParcelable(null);
@@ -230,7 +244,7 @@
*
* @return The id.
*/
- public PrintJobId getId() {
+ public @NonNull PrintJobId getId() {
return mId;
}
@@ -241,7 +255,7 @@
*
* @hide
*/
- public void setId(PrintJobId id) {
+ public void setId(@NonNull PrintJobId id) {
this.mId = id;
}
@@ -250,7 +264,7 @@
*
* @return The label.
*/
- public String getLabel() {
+ public @NonNull String getLabel() {
return mLabel;
}
@@ -261,7 +275,7 @@
*
* @hide
*/
- public void setLabel(String label) {
+ public void setLabel(@NonNull String label) {
mLabel = label;
}
@@ -270,7 +284,7 @@
*
* @return The target printer id.
*/
- public PrinterId getPrinterId() {
+ public @Nullable PrinterId getPrinterId() {
return mPrinterId;
}
@@ -281,7 +295,7 @@
*
* @hide
*/
- public void setPrinterId(PrinterId printerId) {
+ public void setPrinterId(@NonNull PrinterId printerId) {
mPrinterId = printerId;
}
@@ -292,7 +306,7 @@
*
* @hide
*/
- public String getPrinterName() {
+ public @Nullable String getPrinterName() {
return mPrinterName;
}
@@ -303,7 +317,7 @@
*
* @hide
*/
- public void setPrinterName(String printerName) {
+ public void setPrinterName(@NonNull String printerName) {
mPrinterName = printerName;
}
@@ -320,7 +334,7 @@
* @see #STATE_FAILED
* @see #STATE_CANCELED
*/
- public int getState() {
+ public @State int getState() {
return mState;
}
@@ -431,7 +445,7 @@
*
* @return The number of copies or zero if not set.
*/
- public int getCopies() {
+ public @IntRange(from = 0) int getCopies() {
return mCopies;
}
@@ -454,7 +468,7 @@
*
* @return The included pages or <code>null</code> if not set.
*/
- public PageRange[] getPages() {
+ public @Nullable PageRange[] getPages() {
return mPageRanges;
}
@@ -474,7 +488,7 @@
*
* @return The attributes.
*/
- public PrintAttributes getAttributes() {
+ public @NonNull PrintAttributes getAttributes() {
return mAttributes;
}
@@ -713,7 +727,7 @@
* @param prototype Prototype to use as a starting point.
* Can be <code>null</code>.
*/
- public Builder(PrintJobInfo prototype) {
+ public Builder(@Nullable PrintJobInfo prototype) {
mPrototype = (prototype != null)
? new PrintJobInfo(prototype)
: new PrintJobInfo();
@@ -724,7 +738,7 @@
*
* @param copies The number of copies.
*/
- public void setCopies(int copies) {
+ public void setCopies(@IntRange(from = 1) int copies) {
mPrototype.mCopies = copies;
}
@@ -733,7 +747,7 @@
*
* @param attributes The attributes.
*/
- public void setAttributes(PrintAttributes attributes) {
+ public void setAttributes(@NonNull PrintAttributes attributes) {
mPrototype.mAttributes = attributes;
}
@@ -742,7 +756,7 @@
*
* @param pages The included pages.
*/
- public void setPages(PageRange[] pages) {
+ public void setPages(@NonNull PageRange[] pages) {
mPrototype.mPageRanges = pages;
}
@@ -774,7 +788,7 @@
* @param key The option key.
* @param value The option value.
*/
- public void putAdvancedOption(String key, String value) {
+ public void putAdvancedOption(@NonNull String key, @Nullable String value) {
if (mPrototype.mAdvancedOptions == null) {
mPrototype.mAdvancedOptions = new Bundle();
}
@@ -787,7 +801,7 @@
* @param key The option key.
* @param value The option value.
*/
- public void putAdvancedOption(String key, int value) {
+ public void putAdvancedOption(@NonNull String key, int value) {
if (mPrototype.mAdvancedOptions == null) {
mPrototype.mAdvancedOptions = new Bundle();
}
@@ -799,7 +813,7 @@
*
* @return The new instance.
*/
- public PrintJobInfo build() {
+ public @NonNull PrintJobInfo build() {
return mPrototype;
}
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 3fb812e..3eb4874 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -16,11 +16,14 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
+import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -180,6 +183,8 @@
*
* @param context The current context in which to operate.
* @param service The backing system service.
+ * @param userId The user id in which to operate.
+ * @param appId The application id in which to operate.
* @hide
*/
public PrintManager(Context context, IPrintManager service, int userId, int appId) {
@@ -290,6 +295,7 @@
/**
* Gets a print job given its id.
*
+ * @param printJobId The id of the print job.
* @return The print job list.
* @see PrintJob
* @hide
@@ -311,12 +317,35 @@
}
/**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ * @hide
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return null;
+ }
+ try {
+ return mService.getCustomPrinterIcon(printerId, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error getting custom printer icon", re);
+ }
+ return null;
+ }
+
+ /**
* Gets the print jobs for this application.
*
* @return The print job list.
* @see PrintJob
*/
- public List<PrintJob> getPrintJobs() {
+ public @NonNull List<PrintJob> getPrintJobs() {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return Collections.emptyList();
@@ -411,8 +440,9 @@
*
* @see PrintJob
*/
- public PrintJob print(String printJobName, PrintDocumentAdapter documentAdapter,
- PrintAttributes attributes) {
+ public @NonNull PrintJob print(@NonNull String printJobName,
+ @NonNull PrintDocumentAdapter documentAdapter,
+ @Nullable PrintAttributes attributes) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return null;
diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java
index 96f3185..d13879b 100644
--- a/core/java/android/print/PrinterCapabilitiesInfo.java
+++ b/core/java/android/print/PrinterCapabilitiesInfo.java
@@ -16,8 +16,11 @@
package android.print;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.print.PrintAttributes.ColorMode;
+import android.print.PrintAttributes.DuplexMode;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
@@ -121,7 +124,7 @@
*
* @return The media sizes.
*/
- public List<MediaSize> getMediaSizes() {
+ public @NonNull List<MediaSize> getMediaSizes() {
return Collections.unmodifiableList(mMediaSizes);
}
@@ -130,7 +133,7 @@
*
* @return The resolutions.
*/
- public List<Resolution> getResolutions() {
+ public @NonNull List<Resolution> getResolutions() {
return Collections.unmodifiableList(mResolutions);
}
@@ -140,7 +143,7 @@
*
* @return The minimal margins.
*/
- public Margins getMinMargins() {
+ public @NonNull Margins getMinMargins() {
return mMinMargins;
}
@@ -152,7 +155,7 @@
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
*/
- public int getColorModes() {
+ public @ColorMode int getColorModes() {
return mColorModes;
}
@@ -165,7 +168,7 @@
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public int getDuplexModes() {
+ public @DuplexMode int getDuplexModes() {
return mDuplexModes;
}
@@ -174,7 +177,7 @@
*
* @return The default attributes.
*/
- public PrintAttributes getDefaults() {
+ public @NonNull PrintAttributes getDefaults() {
PrintAttributes.Builder builder = new PrintAttributes.Builder();
builder.setMinMargins(mMinMargins);
@@ -425,7 +428,7 @@
*
* @throws IllegalArgumentException If the printer id is <code>null</code>.
*/
- public Builder(PrinterId printerId) {
+ public Builder(@NonNull PrinterId printerId) {
if (printerId == null) {
throw new IllegalArgumentException("printerId cannot be null.");
}
@@ -446,7 +449,7 @@
*
* @see PrintAttributes.MediaSize
*/
- public Builder addMediaSize(MediaSize mediaSize, boolean isDefault) {
+ public @NonNull Builder addMediaSize(@NonNull MediaSize mediaSize, boolean isDefault) {
if (mPrototype.mMediaSizes == null) {
mPrototype.mMediaSizes = new ArrayList<MediaSize>();
}
@@ -474,7 +477,7 @@
*
* @see PrintAttributes.Resolution
*/
- public Builder addResolution(Resolution resolution, boolean isDefault) {
+ public @NonNull Builder addResolution(@NonNull Resolution resolution, boolean isDefault) {
if (mPrototype.mResolutions == null) {
mPrototype.mResolutions = new ArrayList<Resolution>();
}
@@ -502,7 +505,7 @@
*
* @see PrintAttributes.Margins
*/
- public Builder setMinMargins(Margins margins) {
+ public @NonNull Builder setMinMargins(@NonNull Margins margins) {
if (margins == null) {
throw new IllegalArgumentException("margins cannot be null");
}
@@ -532,7 +535,8 @@
* @see PrintAttributes#COLOR_MODE_COLOR
* @see PrintAttributes#COLOR_MODE_MONOCHROME
*/
- public Builder setColorModes(int colorModes, int defaultColorMode) {
+ public @NonNull Builder setColorModes(@ColorMode int colorModes,
+ @ColorMode int defaultColorMode) {
int currentModes = colorModes;
while (currentModes > 0) {
final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -562,7 +566,8 @@
* @see PrintAttributes#DUPLEX_MODE_LONG_EDGE
* @see PrintAttributes#DUPLEX_MODE_SHORT_EDGE
*/
- public Builder setDuplexModes(int duplexModes, int defaultDuplexMode) {
+ public @NonNull Builder setDuplexModes(@DuplexMode int duplexModes,
+ @DuplexMode int defaultDuplexMode) {
int currentModes = duplexModes;
while (currentModes > 0) {
final int currentMode = (1 << Integer.numberOfTrailingZeros(currentModes));
@@ -589,7 +594,7 @@
*
* @throws IllegalStateException If a required attribute was not specified.
*/
- public PrinterCapabilitiesInfo build() {
+ public @NonNull PrinterCapabilitiesInfo build() {
if (mPrototype.mMediaSizes == null || mPrototype.mMediaSizes.isEmpty()) {
throw new IllegalStateException("No media size specified.");
}
diff --git a/core/java/android/print/PrinterId.java b/core/java/android/print/PrinterId.java
index a3f3b2bf..83efe80 100644
--- a/core/java/android/print/PrinterId.java
+++ b/core/java/android/print/PrinterId.java
@@ -16,6 +16,7 @@
package android.print;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
@@ -65,7 +66,7 @@
*
* @return The printer name.
*/
- public String getLocalId() {
+ public @NonNull String getLocalId() {
return mLocalId;
}
diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java
index 7fcc81f..afef9c0 100644
--- a/core/java/android/print/PrinterInfo.java
+++ b/core/java/android/print/PrinterInfo.java
@@ -16,10 +16,26 @@
package android.print;
+import android.annotation.DrawableRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* This class represents the description of a printer. Instances of
* this class are created by print services to report to the system
@@ -30,6 +46,13 @@
*/
public final class PrinterInfo implements Parcelable {
+ /** @hide */
+ @IntDef({
+ STATUS_IDLE, STATUS_BUSY, STATUS_UNAVAILABLE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Status {
+ }
/** Printer status: the printer is idle and ready to print. */
public static final int STATUS_IDLE = 1;
@@ -41,6 +64,18 @@
private PrinterId mId;
+ /** Resource inside the printer's services's package to be used as an icon */
+ private int mIconResourceId;
+
+ /** If a custom icon can be loaded for the printer */
+ private boolean mHasCustomPrinterIcon;
+
+ /** The generation of the icon in the cache. */
+ private int mCustomPrinterIconGen;
+
+ /** Intent that launches the activity showing more information about the printer. */
+ private PendingIntent mInfoIntent;
+
private String mName;
private int mStatus;
@@ -77,6 +112,10 @@
} else {
mCapabilities = null;
}
+ mIconResourceId = other.mIconResourceId;
+ mHasCustomPrinterIcon = other.mHasCustomPrinterIcon;
+ mCustomPrinterIconGen = other.mCustomPrinterIconGen;
+ mInfoIntent = other.mInfoIntent;
}
/**
@@ -84,16 +123,64 @@
*
* @return The printer id.
*/
- public PrinterId getId() {
+ public @NonNull PrinterId getId() {
return mId;
}
/**
+ * Get the icon to be used for this printer. If no per printer icon is available, the printer's
+ * service's icon is returned. If the printer has a custom icon this icon might get requested
+ * asynchronously. Once the icon is loaded the discovery sessions will be notified that the
+ * printer changed.
+ *
+ * @param context The context that will be using the icons
+ * @return The icon to be used for the printer or null if no icon could be found.
+ * @hide
+ */
+ @TestApi
+ public @Nullable Drawable loadIcon(@NonNull Context context) {
+ Drawable drawable = null;
+ PackageManager packageManager = context.getPackageManager();
+
+ if (mHasCustomPrinterIcon) {
+ PrintManager printManager = (PrintManager) context
+ .getSystemService(Context.PRINT_SERVICE);
+
+ Icon icon = printManager.getCustomPrinterIcon(mId);
+
+ if (icon != null) {
+ drawable = icon.loadDrawable(context);
+ }
+ }
+
+ if (drawable == null) {
+ try {
+ String packageName = mId.getServiceName().getPackageName();
+ PackageInfo packageInfo = packageManager.getPackageInfo(packageName, 0);
+ ApplicationInfo appInfo = packageInfo.applicationInfo;
+
+ // If no custom icon is available, try the icon from the resources
+ if (mIconResourceId != 0) {
+ drawable = packageManager.getDrawable(packageName, mIconResourceId, appInfo);
+ }
+
+ // Fall back to the printer's service's icon if no per printer icon could be found
+ if (drawable == null) {
+ drawable = appInfo.loadIcon(packageManager);
+ }
+ } catch (NameNotFoundException e) {
+ }
+ }
+
+ return drawable;
+ }
+
+ /**
* Get the printer name.
*
* @return The printer name.
*/
- public String getName() {
+ public @Nullable String getName() {
return mName;
}
@@ -106,7 +193,7 @@
* @see #STATUS_IDLE
* @see #STATUS_UNAVAILABLE
*/
- public int getStatus() {
+ public @Status int getStatus() {
return mStatus;
}
@@ -115,16 +202,28 @@
*
* @return The description.
*/
- public String getDescription() {
+ public @Nullable String getDescription() {
return mDescription;
}
/**
+ * Get the {@link PendingIntent} that launches the activity showing more information about the
+ * printer.
+ *
+ * @return the {@link PendingIntent} that launches the activity showing more information about
+ * the printer or null if it is not configured
+ * @hide
+ */
+ public @Nullable PendingIntent getInfoIntent() {
+ return mInfoIntent;
+ }
+
+ /**
* Gets the printer capabilities.
*
* @return The capabilities.
*/
- public PrinterCapabilitiesInfo getCapabilities() {
+ public @Nullable PrinterCapabilitiesInfo getCapabilities() {
return mCapabilities;
}
@@ -134,6 +233,10 @@
mStatus = parcel.readInt();
mDescription = parcel.readString();
mCapabilities = parcel.readParcelable(null);
+ mIconResourceId = parcel.readInt();
+ mHasCustomPrinterIcon = parcel.readByte() != 0;
+ mCustomPrinterIconGen = parcel.readInt();
+ mInfoIntent = parcel.readParcelable(null);
}
@Override
@@ -148,6 +251,10 @@
parcel.writeInt(mStatus);
parcel.writeString(mDescription);
parcel.writeParcelable(mCapabilities, flags);
+ parcel.writeInt(mIconResourceId);
+ parcel.writeByte((byte) (mHasCustomPrinterIcon ? 1 : 0));
+ parcel.writeInt(mCustomPrinterIconGen);
+ parcel.writeParcelable(mInfoIntent, flags);
}
@Override
@@ -159,9 +266,61 @@
result = prime * result + mStatus;
result = prime * result + ((mDescription != null) ? mDescription.hashCode() : 0);
result = prime * result + ((mCapabilities != null) ? mCapabilities.hashCode() : 0);
+ result = prime * result + mIconResourceId;
+ result = prime * result + (mHasCustomPrinterIcon ? 1 : 0);
+ result = prime * result + mCustomPrinterIconGen;
+ result = prime * result + ((mInfoIntent != null) ? mInfoIntent.hashCode() : 0);
return result;
}
+ /**
+ * Compare two {@link PrinterInfo printerInfos} in all aspects beside being null and the
+ * {@link #mStatus}.
+ *
+ * @param other the other {@link PrinterInfo}
+ * @return true iff the infos are equivalent
+ * @hide
+ */
+ public boolean equalsIgnoringStatus(PrinterInfo other) {
+ if (mId == null) {
+ if (other.mId != null) {
+ return false;
+ }
+ } else if (!mId.equals(other.mId)) {
+ return false;
+ }
+ if (!TextUtils.equals(mName, other.mName)) {
+ return false;
+ }
+ if (!TextUtils.equals(mDescription, other.mDescription)) {
+ return false;
+ }
+ if (mCapabilities == null) {
+ if (other.mCapabilities != null) {
+ return false;
+ }
+ } else if (!mCapabilities.equals(other.mCapabilities)) {
+ return false;
+ }
+ if (mIconResourceId != other.mIconResourceId) {
+ return false;
+ }
+ if (mHasCustomPrinterIcon != other.mHasCustomPrinterIcon) {
+ return false;
+ }
+ if (mCustomPrinterIconGen != other.mCustomPrinterIconGen) {
+ return false;
+ }
+ if (mInfoIntent == null) {
+ if (other.mInfoIntent != null) {
+ return false;
+ }
+ } else if (!mInfoIntent.equals(other.mInfoIntent)) {
+ return false;
+ }
+ return true;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -174,29 +333,12 @@
return false;
}
PrinterInfo other = (PrinterInfo) obj;
- if (mId == null) {
- if (other.mId != null) {
- return false;
- }
- } else if (!mId.equals(other.mId)) {
- return false;
- }
- if (!TextUtils.equals(mName, other.mName)) {
+ if (!equalsIgnoringStatus(other)) {
return false;
}
if (mStatus != other.mStatus) {
return false;
}
- if (!TextUtils.equals(mDescription, other.mDescription)) {
- return false;
- }
- if (mCapabilities == null) {
- if (other.mCapabilities != null) {
- return false;
- }
- } else if (!mCapabilities.equals(other.mCapabilities)) {
- return false;
- }
return true;
}
@@ -209,6 +351,10 @@
builder.append(", status=").append(mStatus);
builder.append(", description=").append(mDescription);
builder.append(", capabilities=").append(mCapabilities);
+ builder.append(", iconResId=").append(mIconResourceId);
+ builder.append(", hasCustomPrinterIcon=").append(mHasCustomPrinterIcon);
+ builder.append(", customPrinterIconGen=").append(mCustomPrinterIconGen);
+ builder.append(", infoIntent=").append(mInfoIntent);
builder.append("\"}");
return builder.toString();
}
@@ -228,7 +374,7 @@
* @throws IllegalArgumentException If the printer id is null, or the
* printer name is empty or the status is not a valid one.
*/
- public Builder(PrinterId printerId, String name, int status) {
+ public Builder(@NonNull PrinterId printerId, @NonNull String name, @Status int status) {
if (printerId == null) {
throw new IllegalArgumentException("printerId cannot be null.");
}
@@ -249,7 +395,7 @@
*
* @param other Other info from which to start building.
*/
- public Builder(PrinterInfo other) {
+ public Builder(@NonNull PrinterInfo other) {
mPrototype = new PrinterInfo();
mPrototype.copyFrom(other);
}
@@ -264,19 +410,50 @@
* @see PrinterInfo#STATUS_BUSY
* @see PrinterInfo#STATUS_UNAVAILABLE
*/
- public Builder setStatus(int status) {
+ public @NonNull Builder setStatus(@Status int status) {
mPrototype.mStatus = status;
return this;
}
/**
+ * Set a drawable resource as icon for this printer. If no icon is set the printer's
+ * service's icon is used for the printer.
+ *
+ * @param iconResourceId The resource ID of the icon.
+ * @return This builder.
+ * @see PrinterInfo.Builder#setHasCustomPrinterIcon
+ */
+ public @NonNull Builder setIconResourceId(@DrawableRes int iconResourceId) {
+ mPrototype.mIconResourceId = iconResourceId;
+ return this;
+ }
+
+ /**
+ * Declares that the print service can load a custom per printer's icon. If both
+ * {@link PrinterInfo.Builder#setIconResourceId} and a custom icon are set the resource icon
+ * is shown while the custom icon loads but then the custom icon is used. If
+ * {@link PrinterInfo.Builder#setIconResourceId} is not set the printer's service's icon is
+ * shown while loading.
+ * <p>
+ * The icon is requested asynchronously and only when needed via
+ * {@link android.printservice.PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+ * </p>
+ *
+ * @return This builder.
+ */
+ public @NonNull Builder setHasCustomPrinterIcon() {
+ mPrototype.mHasCustomPrinterIcon = true;
+ return this;
+ }
+
+ /**
* Sets the <strong>localized</strong> printer name which
* is shown to the user
*
* @param name The name.
* @return This builder.
*/
- public Builder setName(String name) {
+ public @NonNull Builder setName(@NonNull String name) {
mPrototype.mName = name;
return this;
}
@@ -288,18 +465,30 @@
* @param description The description.
* @return This builder.
*/
- public Builder setDescription(String description) {
+ public @NonNull Builder setDescription(@NonNull String description) {
mPrototype.mDescription = description;
return this;
}
/**
+ * Sets the {@link PendingIntent} that launches an activity showing more information about
+ * the printer.
+ *
+ * @param infoIntent The {@link PendingIntent intent}.
+ * @return This builder.
+ */
+ public @NonNull Builder setInfoIntent(@NonNull PendingIntent infoIntent) {
+ mPrototype.mInfoIntent = infoIntent;
+ return this;
+ }
+
+ /**
* Sets the printer capabilities.
*
* @param capabilities The capabilities.
* @return This builder.
*/
- public Builder setCapabilities(PrinterCapabilitiesInfo capabilities) {
+ public @NonNull Builder setCapabilities(@NonNull PrinterCapabilitiesInfo capabilities) {
mPrototype.mCapabilities = capabilities;
return this;
}
@@ -309,7 +498,7 @@
*
* @return A new {@link PrinterInfo}.
*/
- public PrinterInfo build() {
+ public @NonNull PrinterInfo build() {
return mPrototype;
}
@@ -318,6 +507,19 @@
|| status == STATUS_BUSY
|| status == STATUS_UNAVAILABLE);
}
+
+ /**
+ * Increments the generation number of the custom printer icon. As the {@link PrinterInfo}
+ * does not match the previous one anymore, users of the {@link PrinterInfo} will reload the
+ * icon if needed.
+ *
+ * @return This builder.
+ * @hide
+ */
+ public @NonNull Builder incCustomPrinterIconGen() {
+ mPrototype.mCustomPrinterIconGen++;
+ return this;
+ }
}
public static final Parcelable.Creator<PrinterInfo> CREATOR =
diff --git a/core/java/android/print/pdf/PrintedPdfDocument.java b/core/java/android/print/pdf/PrintedPdfDocument.java
index 2d8aafa..df7c054 100644
--- a/core/java/android/print/pdf/PrintedPdfDocument.java
+++ b/core/java/android/print/pdf/PrintedPdfDocument.java
@@ -16,26 +16,25 @@
package android.print.pdf;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.pdf.PdfDocument;
-import android.graphics.pdf.PdfDocument.Page;
-import android.graphics.pdf.PdfDocument.PageInfo;
import android.print.PrintAttributes;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
/**
- * This class is a helper for creating a PDF file for given print
- * attributes. It is useful for implementing printing via the native
- * Android graphics APIs.
+ * This class is a helper for creating a PDF file for given print attributes. It is useful for
+ * implementing printing via the native Android graphics APIs.
* <p>
- * This class computes the page width, page height, and content rectangle
- * from the provided print attributes and these precomputed values can be
- * accessed via {@link #getPageWidth()}, {@link #getPageHeight()}, and
- * {@link #getPageContentRect()}, respectively. The {@link #startPage(int)}
- * methods creates pages whose {@link PageInfo} is initialized with the
- * precomputed values for width, height, and content rectangle.
+ * This class computes the page width, page height, and content rectangle from the provided print
+ * attributes and these precomputed values can be accessed via {@link #getPageWidth()},
+ * {@link #getPageHeight()}, and {@link #getPageContentRect()}, respectively. The
+ * {@link #startPage(int)} methods creates pages whose
+ * {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo} is initialized with the precomputed
+ * values for width, height, and content rectangle.
* <p>
* A typical use of the APIs looks like this:
* </p>
@@ -81,7 +80,7 @@
* @param context Context instance for accessing resources.
* @param attributes The print attributes.
*/
- public PrintedPdfDocument(Context context, PrintAttributes attributes) {
+ public PrintedPdfDocument(@NonNull Context context, @NonNull PrintAttributes attributes) {
MediaSize mediaSize = attributes.getMediaSize();
// Compute the size of the target canvas from the attributes.
@@ -105,28 +104,28 @@
}
/**
- * Starts a new page. The page is created using width, height and content
- * rectangle computed from the print attributes passed in the constructor
- * and the given page number to create an appropriate {@link PageInfo}.
+ * Starts a new page. The page is created using width, height and content rectangle computed
+ * from the print attributes passed in the constructor and the given page number to create an
+ * appropriate {@link android.graphics.pdf.PdfDocument.PageInfo PageInfo}.
* <p>
- * After the page is created you can draw arbitrary content on the page's
- * canvas which you can get by calling {@link Page#getCanvas() Page.getCanvas()}.
+ * After the page is created you can draw arbitrary content on the page's canvas which you can
+ * get by calling {@link android.graphics.pdf.PdfDocument.Page#getCanvas() Page.getCanvas()}.
* After you are done drawing the content you should finish the page by calling
- * {@link #finishPage(Page)}. After the page is finished you should no longer
- * access the page or its canvas.
+ * {@link #finishPage(Page)}. After the page is finished you should no longer access the page or
+ * its canvas.
* </p>
* <p>
- * <strong>Note:</strong> Do not call this method after {@link #close()}.
- * Also do not call this method if the last page returned by this method
- * is not finished by calling {@link #finishPage(Page)}.
+ * <strong>Note:</strong> Do not call this method after {@link #close()}. Also do not call this
+ * method if the last page returned by this method is not finished by calling
+ * {@link #finishPage(Page)}.
* </p>
*
- * @param pageNumber The page number. Must be a positive value.
+ * @param pageNumber The page number. Must be a non negative.
* @return A blank page.
*
* @see #finishPage(Page)
*/
- public Page startPage(int pageNumber) {
+ public @NonNull Page startPage(@IntRange(from = 0) int pageNumber) {
PageInfo pageInfo = new PageInfo
.Builder(mPageWidth, mPageHeight, pageNumber)
.setContentRect(mContentRect)
@@ -139,7 +138,7 @@
*
* @return The page width in PostScript points (1/72th of an inch).
*/
- public int getPageWidth() {
+ public @IntRange(from = 0) int getPageWidth() {
return mPageWidth;
}
@@ -148,7 +147,7 @@
*
* @return The page height in PostScript points (1/72th of an inch).
*/
- public int getPageHeight() {
+ public @IntRange(from = 0) int getPageHeight() {
return mPageHeight;
}
@@ -158,7 +157,7 @@
*
* @return The content rectangle.
*/
- public Rect getPageContentRect() {
+ public @NonNull Rect getPageContentRect() {
return mContentRect;
}
}
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
new file mode 100644
index 0000000..ea9ea8b
--- /dev/null
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.printservice;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.os.RemoteException;
+import android.print.PrinterId;
+import android.util.Log;
+
+
+/**
+ * Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
+ */
+public class CustomPrinterIconCallback {
+ /** The printer the call back is for */
+ private final @NonNull PrinterId mPrinterId;
+ private final @NonNull IPrintServiceClient mObserver;
+ private static final String LOG_TAG = "CustomPrinterIconCallback";
+
+ /**
+ * Create a callback class to be used once a icon is loaded
+ *
+ * @param printerId The printer the icon should be loaded for
+ * @param observer The observer that needs to be notified about the update.
+ */
+ CustomPrinterIconCallback(@NonNull PrinterId printerId, @NonNull IPrintServiceClient observer) {
+ mPrinterId = printerId;
+ mObserver = observer;
+ }
+
+ /**
+ * Provide a new icon for a printer. Can be called more than once to update the icon.
+ *
+ * @param icon The new icon for the printer or null to unset the current icon
+ * @return true iff the icon could be updated
+ */
+ public boolean onCustomPrinterIconLoaded(@Nullable Icon icon) {
+ try {
+ mObserver.onCustomPrinterIconLoaded(mPrinterId, icon);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG , "Could not update icon", e);
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/core/java/android/printservice/IPrintService.aidl b/core/java/android/printservice/IPrintService.aidl
index ee36619..3750d7a 100644
--- a/core/java/android/printservice/IPrintService.aidl
+++ b/core/java/android/printservice/IPrintService.aidl
@@ -10,7 +10,7 @@
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific languagÿe governing permissions and
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
@@ -35,6 +35,15 @@
void stopPrinterDiscovery();
void validatePrinters(in List<PrinterId> printerIds);
void startPrinterStateTracking(in PrinterId printerId);
+
+ /**
+ * Request the custom icon for a printer.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void requestCustomPrinterIcon(in PrinterId printerId);
+
void stopPrinterStateTracking(in PrinterId printerId);
void destroyPrinterDiscoverySession();
}
diff --git a/core/java/android/printservice/IPrintServiceClient.aidl b/core/java/android/printservice/IPrintServiceClient.aidl
index b4baa48..0ae1e18 100644
--- a/core/java/android/printservice/IPrintServiceClient.aidl
+++ b/core/java/android/printservice/IPrintServiceClient.aidl
@@ -16,6 +16,7 @@
package android.printservice;
+import android.graphics.drawable.Icon;
import android.os.ParcelFileDescriptor;
import android.print.PrintJobInfo;
import android.print.PrinterId;
@@ -53,4 +54,13 @@
void onPrintersAdded(in ParceledListSlice printers);
void onPrintersRemoved(in ParceledListSlice printerIds);
+
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void onCustomPrinterIconLoaded(in PrinterId printerId, in Icon icon);
}
diff --git a/core/java/android/printservice/PrintDocument.java b/core/java/android/printservice/PrintDocument.java
index e43f2a8..0121ae1 100644
--- a/core/java/android/printservice/PrintDocument.java
+++ b/core/java/android/printservice/PrintDocument.java
@@ -16,6 +16,8 @@
package android.printservice;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.PrintDocumentInfo;
@@ -54,7 +56,7 @@
*
* @return The document info.
*/
- public PrintDocumentInfo getInfo() {
+ public @NonNull PrintDocumentInfo getInfo() {
PrintService.throwIfNotCalledOnMainThread();
return mInfo;
}
@@ -69,7 +71,7 @@
*
* @return A file descriptor for reading the data.
*/
- public ParcelFileDescriptor getData() {
+ public @Nullable ParcelFileDescriptor getData() {
PrintService.throwIfNotCalledOnMainThread();
ParcelFileDescriptor source = null;
ParcelFileDescriptor sink = null;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 86fc292..6414b6a 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -344,7 +344,7 @@
* @return True if the tag was set, false otherwise.
*/
@MainThread
- public boolean setTag(String tag) {
+ public boolean setTag(@NonNull String tag) {
PrintService.throwIfNotCalledOnMainThread();
if (isInImmutableState()) {
return false;
@@ -364,7 +364,8 @@
*
* @see #setTag(String)
*/
- public String getTag() {
+ @MainThread
+ public @Nullable String getTag() {
PrintService.throwIfNotCalledOnMainThread();
return getInfo().getTag();
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 6295822..d0037b7 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
@@ -191,30 +192,29 @@
/**
* If you declared an optional activity with advanced print options via the
- * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
- * attribute, this extra is used to pass in the currently constructed {@link
- * PrintJobInfo} to your activity allowing you to modify it. After you are
- * done, you must return the modified {@link PrintJobInfo} via the same extra.
+ * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity} attribute,
+ * this extra is used to pass in the currently constructed {@link PrintJobInfo} to your activity
+ * allowing you to modify it. After you are done, you must return the modified
+ * {@link PrintJobInfo} via the same extra.
* <p>
- * You cannot modify the passed in {@link PrintJobInfo} directly, rather you
- * should build another one using the {@link PrintJobInfo.Builder} class. You
- * can specify any standard properties and add advanced, printer specific,
- * ones via {@link PrintJobInfo.Builder#putAdvancedOption(String, String)
- * PrintJobInfo.Builder.putAdvancedOption(String, String)} and {@link
- * PrintJobInfo.Builder#putAdvancedOption(String, int)
- * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options
- * are not interpreted by the system, they will not be visible to applications,
- * and can only be accessed by your print service via {@link
- * PrintJob#getAdvancedStringOption(String) PrintJob.getAdvancedStringOption(String)}
- * and {@link PrintJob#getAdvancedIntOption(String) PrintJob.getAdvancedIntOption(String)}.
+ * You cannot modify the passed in {@link PrintJobInfo} directly, rather you should build
+ * another one using the {@link android.print.PrintJobInfo.Builder PrintJobInfo.Builder} class.
+ * You can specify any standard properties and add advanced, printer specific, ones via
+ * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, String)
+ * PrintJobInfo.Builder.putAdvancedOption(String, String)} and
+ * {@link android.print.PrintJobInfo.Builder#putAdvancedOption(String, int)
+ * PrintJobInfo.Builder.putAdvancedOption(String, int)}. The advanced options are not
+ * interpreted by the system, they will not be visible to applications, and can only be accessed
+ * by your print service via {@link PrintJob#getAdvancedStringOption(String)
+ * PrintJob.getAdvancedStringOption(String)} and {@link PrintJob#getAdvancedIntOption(String)
+ * PrintJob.getAdvancedIntOption(String)}.
* </p>
* <p>
- * If the advanced print options activity offers changes to the standard print
- * options, you can get the current {@link android.print.PrinterInfo} using the
- * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user
- * with UI options supported by the current printer. For example, if the current
- * printer does not support a given media size, you should not offer it in the
- * advanced print options UI.
+ * If the advanced print options activity offers changes to the standard print options, you can
+ * get the current {@link android.print.PrinterInfo PrinterInfo} using the
+ * {@link #EXTRA_PRINTER_INFO} extra which will allow you to present the user with UI options
+ * supported by the current printer. For example, if the current printer does not support a
+ * given media size, you should not offer it in the advanced print options UI.
* </p>
*
* @see #EXTRA_PRINTER_INFO
@@ -275,9 +275,10 @@
/**
* Callback asking you to create a new {@link PrinterDiscoverySession}.
*
+ * @return The created session.
* @see PrinterDiscoverySession
*/
- protected abstract PrinterDiscoverySession onCreatePrinterDiscoverySession();
+ protected abstract @Nullable PrinterDiscoverySession onCreatePrinterDiscoverySession();
/**
* Called when cancellation of a print job is requested. The service
@@ -368,6 +369,7 @@
mHandler.sendEmptyMessage(ServiceHandler.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
}
+ @Override
public void startPrinterDiscovery(List<PrinterId> priorityList) {
mHandler.obtainMessage(ServiceHandler.MSG_START_PRINTER_DISCOVERY,
priorityList).sendToTarget();
@@ -391,6 +393,12 @@
}
@Override
+ public void requestCustomPrinterIcon(PrinterId printerId) {
+ mHandler.obtainMessage(ServiceHandler.MSG_REQUEST_CUSTOM_PRINTER_ICON,
+ printerId).sendToTarget();
+ }
+
+ @Override
public void stopPrinterStateTracking(PrinterId printerId) {
mHandler.obtainMessage(ServiceHandler.MSG_STOP_PRINTER_STATE_TRACKING,
printerId).sendToTarget();
@@ -423,10 +431,11 @@
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
public static final int MSG_VALIDATE_PRINTERS = 5;
public static final int MSG_START_PRINTER_STATE_TRACKING = 6;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7;
- public static final int MSG_ON_PRINTJOB_QUEUED = 8;
- public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9;
- public static final int MSG_SET_CLIENT = 10;
+ public static final int MSG_REQUEST_CUSTOM_PRINTER_ICON = 7;
+ public static final int MSG_STOP_PRINTER_STATE_TRACKING = 8;
+ public static final int MSG_ON_PRINTJOB_QUEUED = 9;
+ public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 10;
+ public static final int MSG_SET_CLIENT = 11;
public ServiceHandler(Looper looper) {
super(looper, null, true);
@@ -508,6 +517,17 @@
}
} break;
+ case MSG_REQUEST_CUSTOM_PRINTER_ICON: {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "MSG_REQUEST_CUSTOM_PRINTER_ICON "
+ + getPackageName());
+ }
+ if (mDiscoverySession != null) {
+ PrinterId printerId = (PrinterId) message.obj;
+ mDiscoverySession.requestCustomPrinterIcon(printerId);
+ }
+ } break;
+
case MSG_STOP_PRINTER_STATE_TRACKING: {
if (DEBUG) {
Log.i(LOG_TAG, "MSG_STOP_PRINTER_STATE_TRACKING "
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index a2c6c09e..91e01f2 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -94,12 +95,21 @@
}
/**
+ * Return the component name for this print service.
+ *
+ * @return The component name for this print service.
+ */
+ public @NonNull ComponentName getComponentName() {
+ return new ComponentName(mResolveInfo.serviceInfo.packageName,
+ mResolveInfo.serviceInfo.name);
+ }
+
+ /**
* Creates a new instance.
*
* @param resolveInfo The service resolve info.
* @param context Context for accessing resources.
- * @throws XmlPullParserException If a XML parsing error occurs.
- * @throws IOException If a I/O error occurs.
+ * @return The created instance.
*/
public static PrintServiceInfo create(ResolveInfo resolveInfo, Context context) {
String settingsActivityName = null;
@@ -220,10 +230,12 @@
/**
* {@inheritDoc}
*/
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel parcel, int flagz) {
parcel.writeString(mId);
parcel.writeParcelable(mResolveInfo, 0);
@@ -275,10 +287,12 @@
public static final Parcelable.Creator<PrintServiceInfo> CREATOR =
new Parcelable.Creator<PrintServiceInfo>() {
+ @Override
public PrintServiceInfo createFromParcel(Parcel parcel) {
return new PrintServiceInfo(parcel);
}
+ @Override
public PrintServiceInfo[] newArray(int size) {
return new PrintServiceInfo[size];
}
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 17cb68f..cd5a903 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.NonNull;
import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
import android.print.PrinterCapabilitiesInfo;
@@ -138,7 +139,7 @@
* @see #removePrinters(List)
* @see #isDestroyed()
*/
- public final List<PrinterInfo> getPrinters() {
+ public final @NonNull List<PrinterInfo> getPrinters() {
PrintService.throwIfNotCalledOnMainThread();
if (mIsDestroyed) {
return Collections.emptyList();
@@ -161,7 +162,7 @@
* @see #getPrinters()
* @see #isDestroyed()
*/
- public final void addPrinters(List<PrinterInfo> printers) {
+ public final void addPrinters(@NonNull List<PrinterInfo> printers) {
PrintService.throwIfNotCalledOnMainThread();
// If the session is destroyed - nothing do to.
@@ -225,7 +226,7 @@
* @see #getPrinters()
* @see #isDestroyed()
*/
- public final void removePrinters(List<PrinterId> printerIds) {
+ public final void removePrinters(@NonNull List<PrinterId> printerIds) {
PrintService.throwIfNotCalledOnMainThread();
// If the session is destroyed - nothing do to.
@@ -350,7 +351,7 @@
* @see #removePrinters(List)
* @see #isPrinterDiscoveryStarted()
*/
- public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+ public abstract void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList);
/**
* Callback notifying you that you should stop printer discovery.
@@ -372,10 +373,10 @@
*
* @param printerIds The printers to validate.
*
- * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+ * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
- public abstract void onValidatePrinters(List<PrinterId> printerIds);
+ public abstract void onValidatePrinters(@NonNull List<PrinterId> printerIds);
/**
* Callback asking you to start tracking the state of a printer. Tracking
@@ -400,10 +401,24 @@
* @param printerId The printer to start tracking.
*
* @see #onStopPrinterStateTracking(PrinterId)
- * @see PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
+ * @see android.print.PrinterInfo.Builder#setCapabilities(PrinterCapabilitiesInfo)
* PrinterInfo.Builder.setCapabilities(PrinterCapabilitiesInfo)
*/
- public abstract void onStartPrinterStateTracking(PrinterId printerId);
+ public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
+
+ /**
+ * Request the custom icon for a printer. Once the icon is available use
+ * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
+ * service.
+ *
+ * @param printerId The printer to icon belongs to.
+ * @param callback Callback for returning the icon to the print spooler.
+ *
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+ @NonNull CustomPrinterIconCallback callback) {
+ }
/**
* Callback asking you to stop tracking the state of a printer. The passed
@@ -414,7 +429,7 @@
*
* @see #onStartPrinterStateTracking(PrinterId)
*/
- public abstract void onStopPrinterStateTracking(PrinterId printerId);
+ public abstract void onStopPrinterStateTracking(@NonNull PrinterId printerId);
/**
* Gets the printers that should be tracked. These are printers that are
@@ -434,7 +449,7 @@
* @see #onStopPrinterStateTracking(PrinterId)
* @see #isDestroyed()
*/
- public final List<PrinterId> getTrackedPrinters() {
+ public final @NonNull List<PrinterId> getTrackedPrinters() {
PrintService.throwIfNotCalledOnMainThread();
if (mIsDestroyed) {
return Collections.emptyList();
@@ -476,7 +491,7 @@
return mIsDiscoveryStarted;
}
- void startPrinterDiscovery(List<PrinterId> priorityList) {
+ void startPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
if (!mIsDestroyed) {
mIsDiscoveryStarted = true;
sendOutOfDiscoveryPeriodPrinterChanges();
@@ -494,13 +509,13 @@
}
}
- void validatePrinters(List<PrinterId> printerIds) {
+ void validatePrinters(@NonNull List<PrinterId> printerIds) {
if (!mIsDestroyed && mObserver != null) {
onValidatePrinters(printerIds);
}
}
- void startPrinterStateTracking(PrinterId printerId) {
+ void startPrinterStateTracking(@NonNull PrinterId printerId) {
if (!mIsDestroyed && mObserver != null
&& !mTrackedPrinters.contains(printerId)) {
mTrackedPrinters.add(printerId);
@@ -508,7 +523,21 @@
}
}
- void stopPrinterStateTracking(PrinterId printerId) {
+ /**
+ * Request the custom icon for a printer.
+ *
+ * @param printerId The printer to icon belongs to.
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
+ if (!mIsDestroyed && mObserver != null) {
+ CustomPrinterIconCallback callback = new CustomPrinterIconCallback(printerId,
+ mObserver);
+ onRequestCustomPrinterIcon(printerId, callback);
+ }
+ }
+
+ void stopPrinterStateTracking(@NonNull PrinterId printerId) {
if (!mIsDestroyed && mObserver != null
&& mTrackedPrinters.remove(printerId)) {
onStopPrinterStateTracking(printerId);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 1d4d572..6a5d857c 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -421,6 +421,13 @@
public static final String ADD_FOR_ALL_USERS = "add_for_all_users";
/**
+ * The date the row is last inserted, updated, or marked as deleted, in milliseconds
+ * since the epoch. Read only.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String LAST_MODIFIED = "last_modified";
+
+ /**
* If a successful call is made that is longer than this duration, update the phone number
* in the ContactsProvider with the normalized version of the number, based on the user's
* current country code.
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 084ff77..a401ac2 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -230,7 +230,6 @@
* @see #FLAG_SUPPORTS_WRITE
* @see #FLAG_SUPPORTS_DELETE
* @see #FLAG_SUPPORTS_THUMBNAIL
- * @see #FLAG_SUPPORTS_TYPED_DOCUMENT
* @see #FLAG_DIR_PREFERS_GRID
* @see #FLAG_DIR_PREFERS_LAST_MODIFIED
* @see #FLAG_VIRTUAL_DOCUMENT
@@ -349,15 +348,6 @@
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
/**
- * Flag indicating that a document can be converted to alternative types.
- *
- * @see #COLUMN_FLAGS
- * @see DocumentsProvider#openTypedDocument(String, String, Bundle,
- * android.os.CancellationSignal)
- */
- public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 1 << 9;
-
- /**
* Flag indicating that a document is virtual, and doesn't have byte
* representation in the MIME type specified as {@link #COLUMN_MIME_TYPE}.
*
@@ -366,7 +356,7 @@
* @see DocumentsProvider#openTypedDocument(String, String, Bundle,
* android.os.CancellationSignal)
*/
- public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 10;
+ public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 9;
/**
* Flag indicating that a document is an archive, and it's contents can be
@@ -378,7 +368,7 @@
* @see #COLUMN_FLAGS
* @see DocumentsProvider#queryChildDocuments(String, String[], String)
*/
- public static final int FLAG_ARCHIVE = 1 << 11;
+ public static final int FLAG_ARCHIVE = 1 << 10;
/**
* Flag indicating that document titles should be hidden when viewing
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index e25ba35..94b4157 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -517,13 +517,12 @@
* provider.
* @param signal used by the caller to signal if the request should be
* cancelled. May be null.
- * @see Document#FLAG_SUPPORTS_TYPED_DOCUMENT
*/
@SuppressWarnings("unused")
public AssetFileDescriptor openTypedDocument(
String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
throws FileNotFoundException {
- throw new UnsupportedOperationException("Typed documents not supported");
+ throw new FileNotFoundException("The requested MIME type is not supported.");
}
/**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 48b3c1a..89ac27c9a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -384,8 +384,14 @@
public interface MediaColumns extends BaseColumns {
/**
- * The data stream for the file
- * <P>Type: DATA STREAM</P>
+ * Path to the file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly access
+ * this path. Instead of trying to open this path directly, apps should
+ * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -1149,8 +1155,15 @@
public static final String DEFAULT_SORT_ORDER = "image_id ASC";
/**
- * The data stream for the thumbnail
- * <P>Type: DATA STREAM</P>
+ * Path to the thumbnail file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -1596,8 +1609,15 @@
public static final String NAME = "name";
/**
- * The data stream for the playlist file
- * <P>Type: DATA STREAM</P>
+ * Path to the playlist file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
@@ -2192,8 +2212,15 @@
public static final String DEFAULT_SORT_ORDER = "video_id ASC";
/**
- * The data stream for the thumbnail
- * <P>Type: DATA STREAM</P>
+ * Path to the thumbnail file on disk.
+ * <p>
+ * Note that apps may not have filesystem permissions to directly
+ * access this path. Instead of trying to open this path directly,
+ * apps should use
+ * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+ * access.
+ * <p>
+ * Type: TEXT
*/
public static final String DATA = "_data";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a1e5510..e1391da 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -19,6 +19,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
@@ -1092,6 +1093,22 @@
public static final String ACTION_HOME_SETTINGS
= "android.settings.HOME_SETTINGS";
+
+
+ /**
+ * Activity Action: Show Default apps settings.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS
+ = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
+
/**
* Activity Action: Show notification settings.
*
@@ -1122,6 +1139,19 @@
/** @hide */ public static final String EXTRA_APP_UID = "app_uid";
/** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package";
+ /**
+ * Activity Action: Show a dialog with disabled by policy message.
+ * <p> If an user action is disabled by policy, this dialog can be triggered to let
+ * the user know about this.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
+ = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
+
// End of Intent actions for Settings
/**
@@ -4333,6 +4363,7 @@
* The currently selected voice interaction service flattened ComponentName.
* @hide
*/
+ @TestApi
public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
/**
@@ -4956,19 +4987,22 @@
/**
* List of the enabled print services.
+ *
+ * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade
+ * from pre-N.
+ *
* @hide
*/
public static final String ENABLED_PRINT_SERVICES =
"enabled_print_services";
/**
- * List of the system print services we enabled on first boot. On
- * first boot we enable all system, i.e. bundled print services,
- * once, so they work out-of-the-box.
+ * List of the disabled print services.
+ *
* @hide
*/
- public static final String ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES =
- "enabled_on_first_boot_system_print_services";
+ public static final String DISABLED_PRINT_SERVICES =
+ "disabled_print_services";
/**
* Setting to always use the default text-to-speech settings regardless
@@ -5617,6 +5651,15 @@
public static final String ASSIST_SCREENSHOT_ENABLED = "assist_screenshot_enabled";
/**
+ * Names of the service component that the current user has explicitly allowed to
+ * see and change the importance of all of the user's notifications.
+ *
+ * @hide
+ */
+ public static final String ENABLED_NOTIFICATION_ASSISTANT
+ = "enabled_notification_assistant";
+
+ /**
* Names of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
*
@@ -6108,6 +6151,13 @@
public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
/**
+ * A Long representing a bitmap of profiles that should be disabled when bluetooth starts.
+ * See {@link android.bluetooth.BluetoothProfile}.
+ * {@hide}
+ */
+ public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
+
+ /**
* The policy for deciding when Wi-Fi should go to sleep (which will in
* turn switch to using the mobile data as an Internet connection).
* <p>
@@ -6342,6 +6392,13 @@
public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
= "force_resizable_activities";
+ /**
+ * Whether to enable experimental freeform support for windows.
+ * @hide
+ */
+ public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
+ = "enable_freeform_support";
+
/**
* Whether user has enabled development settings.
*/
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 76eaea9..24683cb 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -245,6 +245,13 @@
public static final String DELETED = "deleted";
/**
+ * The date the row is last inserted, updated, or marked as deleted, in milliseconds
+ * since the epoch. Read only.
+ * <P>Type: INTEGER (long)</P>
+ */
+ public static final String LAST_MODIFIED = "last_modified";
+
+ /**
* A convenience method to build voicemail URI specific to a source package by appending
* {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
*/
@@ -449,6 +456,26 @@
public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2;
/**
+ * Amount of resource that is used by existing voicemail in the visual voicemail inbox,
+ * or {@link #QUOTA_UNAVAILABLE}. Unit is not specified.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String QUOTA_OCCUPIED = "quota_occupied";
+
+ /**
+ * Total resource in the visual voicemail inbox that can be used, or
+ * {@link #QUOTA_UNAVAILABLE}. Unit is not specified.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String QUOTA_TOTAL = "quota_total";
+
+ /**
+ * Value for {@link #QUOTA_OCCUPIED} and {@link #QUOTA_TOTAL} to indicate that no
+ * information is available.
+ */
+ public static final int QUOTA_UNAVAILABLE = -1;
+
+ /**
* A convenience method to build status URI specific to a source package by appending
* {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
*/
@@ -488,6 +515,39 @@
}
/**
+ * A helper method to set the quota of a voicemail source. Unit is unspecified.
+ *
+ * @param context The context from the package calling the method. This will be the source.
+ * @param accountHandle The handle for the account the source is associated with.
+ * @param occupied See {@link Status#QUOTA_OCCUPIED}
+ * @param total See {@link Status#QUOTA_TOTAL}
+ */
+ public static void setQuota(Context context, PhoneAccountHandle accountHandle, int occupied,
+ int total) {
+ if (occupied == QUOTA_UNAVAILABLE && total == QUOTA_UNAVAILABLE) {
+ return;
+ }
+ ContentValues values = new ContentValues();
+ values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
+ accountHandle.getComponentName().flattenToString());
+ values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
+ if (occupied != QUOTA_UNAVAILABLE) {
+ values.put(Status.QUOTA_OCCUPIED,occupied);
+ }
+ if (total != QUOTA_UNAVAILABLE) {
+ values.put(Status.QUOTA_TOTAL,total);
+ }
+
+ ContentResolver contentResolver = context.getContentResolver();
+ Uri statusUri = buildSourceUri(context.getPackageName());
+ if (isStatusPresent(contentResolver, statusUri)) {
+ contentResolver.update(statusUri, values, null, null);
+ } else {
+ contentResolver.insert(statusUri, values);
+ }
+ }
+
+ /**
* Determines if a voicemail source exists in the status table.
*
* @param contentResolver A content resolver constructed from the appropriate context.
diff --git a/core/java/android/security/FrameworkNetworkSecurityPolicy.java b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
index e3dac5e..83f173ec 100644
--- a/core/java/android/security/FrameworkNetworkSecurityPolicy.java
+++ b/core/java/android/security/FrameworkNetworkSecurityPolicy.java
@@ -32,4 +32,9 @@
public boolean isCleartextTrafficPermitted() {
return mCleartextTrafficPermitted;
}
+
+ @Override
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return isCleartextTrafficPermitted();
+ }
}
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 7991d37..37ec725 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -43,7 +43,7 @@
/**
* Returns whether cleartext network traffic (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP --
- * without TLS or STARTTLS) is permitted for this process.
+ * without TLS or STARTTLS) is permitted for all network communication from this process.
*
* <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and
* FTP stacks, {@link android.app.DownloadManager}, {@link android.media.MediaPlayer}) will
@@ -64,6 +64,17 @@
}
/**
+ * Returns whether cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP -- without
+ * TLS or STARTTLS) is permitted for communicating with {@code hostname} for this process.
+ *
+ * @see #isCleartextTrafficPermitted()
+ */
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return libcore.net.NetworkSecurityPolicy.getInstance()
+ .isCleartextTrafficPermitted(hostname);
+ }
+
+ /**
* Sets whether cleartext network traffic is permitted for this process.
*
* <p>This method is used by the platform early on in the application's initialization to set
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 71d9d5d..4de36cd 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -120,6 +120,32 @@
return mTrustManager;
}
+ /**
+ * Returns {@code true} if cleartext traffic is permitted for this application, which is the
+ * case only if all configurations permit cleartext traffic. For finer-grained policy use
+ * {@link #isCleartextTrafficPermitted(String)}.
+ */
+ public boolean isCleartextTrafficPermitted() {
+ ensureInitialized();
+ if (mConfigs != null) {
+ for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+ if (!entry.second.isCleartextTrafficPermitted()) {
+ return false;
+ }
+ }
+ }
+
+ return mDefaultConfig.isCleartextTrafficPermitted();
+ }
+
+ /**
+ * Returns {@code true} if cleartext traffic is permitted for this application when connecting
+ * to {@code hostname}.
+ */
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return getConfigForHostname(hostname).isCleartextTrafficPermitted();
+ }
+
private void ensureInitialized() {
synchronized(mLock) {
if (mInitialized) {
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
new file mode 100644
index 0000000..e7d17c2
--- /dev/null
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.security.net.config;
+
+/**
+ * {@link libcore.net.NetworkSecurityPolicy} based on an {@link ApplicationConfig}.
+ *
+ * @hide
+ */
+public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+ private final ApplicationConfig mConfig;
+
+ public ConfigNetworkSecurityPolicy(ApplicationConfig config) {
+ mConfig = config;
+ }
+
+ @Override
+ public boolean isCleartextTrafficPermitted() {
+ return mConfig.isCleartextTrafficPermitted();
+ }
+
+ @Override
+ public boolean isCleartextTrafficPermitted(String hostname) {
+ return mConfig.isCleartextTrafficPermitted(hostname);
+ }
+}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index 5ebc7ac..0f66873 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -40,5 +40,6 @@
throw new RuntimeException("Failed to install provider as highest priority provider."
+ " Provider was installed at position " + pos);
}
+ libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
}
}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index e6bf6ba..a0de17f 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,6 +23,7 @@
/** @hide */
oneway interface INotificationListener
{
+ // listeners and assistants
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
@@ -31,4 +32,11 @@
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
+
+ // assistants only
+ void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+ void onNotificationVisibilityChanged(String key, long time, boolean visible);
+ void onNotificationClick(String key, long time);
+ void onNotificationActionClick(String key, long time, int actionIndex);
+ void onNotificationRemovedReason(String key, long time, int reason);
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 5d1317c..3a8956e 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -16,8 +16,15 @@
package android.service.notification;
+import android.annotation.SdkConstant;
import android.app.Notification;
+import android.content.Intent;
import android.net.Uri;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
/**
* A service that helps the user manage notifications by modifying the
@@ -35,6 +42,15 @@
* </service></pre>
*/
public abstract class NotificationAssistantService extends NotificationListenerService {
+ private static final String TAG = "NotificationAssistant";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE
+ = "android.service.notification.NotificationAssistantService";
+
/** Notification was canceled by the status bar reporting a click. */
public static final int REASON_DELEGATE_CLICK = 1;
@@ -96,6 +112,14 @@
}
}
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mWrapper == null) {
+ mWrapper = new NotificationAssistantWrapper();
+ }
+ return mWrapper;
+ }
+
/**
* A notification was posted by an app. Called before alert.
*
@@ -163,7 +187,13 @@
*/
public final void adjustImportance(String key, Adjustment adjustment)
{
- // TODO: pack up the adjustment and send it to the NotificationManager.
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
+ adjustment.mImportance, adjustment.mExplanation);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
}
/**
@@ -171,7 +201,7 @@
* be fired when the host notification is deleted, or when this annotation
* is removed or replaced.
*
- * @param key the notification key
+ * @param key the key of the notification to be annotated
* @param annotation the new annotation object
*/
public final void setAnnotation(String key, Notification annotation)
@@ -182,10 +212,74 @@
/**
* Remove the annotation from a notification.
*
- * @param key the notification key
+ * @param key the key of the notification to be cleansed of annotatons
*/
public final void clearAnnotation(String key)
{
// TODO: ask the NotificationManager to clear the annotation.
}
+
+ private class NotificationAssistantWrapper extends NotificationListenerWrapper {
+ @Override
+ public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+ int importance, boolean user) throws RemoteException {
+ StatusBarNotification sbn;
+ try {
+ sbn = sbnHolder.get();
+ } catch (RemoteException e) {
+ Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+ return;
+ }
+
+ try {
+ Adjustment adjustment =
+ NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
+ if (adjustment != null) {
+ adjustImportance(sbn.getKey(), adjustment);
+ }
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationEnqueued", t);
+ }
+ }
+
+ @Override
+ public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
+ visible);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
+ }
+ }
+
+ @Override
+ public void onNotificationClick(String key, long time) throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationClick(key, time);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationClick", t);
+ }
+ }
+
+ @Override
+ public void onNotificationActionClick(String key, long time, int actionIndex)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationActionClick", t);
+ }
+ }
+
+ @Override
+ public void onNotificationRemovedReason(String key, long time, int reason)
+ throws RemoteException {
+ try {
+ NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
+ } catch (Throwable t) {
+ Log.w(TAG, "Error running onNotificationRemoved", t);
+ }
+ }
+ }
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 232d4fe..b42d9ea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,6 +15,7 @@
*/
package android.service.notification;
+import android.service.notification.IStatusBarNotificationHolder;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
@@ -60,6 +61,16 @@
* <action android:name="android.service.notification.NotificationListenerService" />
* </intent-filter>
* </service></pre>
+ * <p> Typically, while enabled in user settings, this service will be bound on boot or when a
+ * settings change occurs that could affect whether this service should run. However, for some
+ * system usage modes, the you may instead specify that this service is instead bound and unbound
+ * in response to mode changes by including a category in the intent filter. Currently
+ * supported categories are:
+ * <ul>
+ * <li>{@link #CATEGORY_VR_NOTIFICATIONS} - this service is bound when an Activity has enabled
+ * VR mode. {@see android.app.Activity#setVrMode(boolean)}.</li>
+ * </ul>
+ * </p>
*/
public abstract class NotificationListenerService extends Service {
// TAG = "NotificationListenerService[MySubclass]"
@@ -112,6 +123,8 @@
NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
public static final int SUPPRESSED_EFFECT_PEEK =
NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+ public static final int SUPPRESSED_EFFECT_SCREEN_ON =
+ NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
/**
* The full trim of the StatusBarNotification including all its features.
@@ -141,7 +154,8 @@
@SystemApi
public static final int TRIM_LIGHT = 1;
- private INotificationListenerWrapper mWrapper = null;
+ /** @hide */
+ protected NotificationListenerWrapper mWrapper = null;
private RankingMap mRankingMap;
private INotificationManager mNoMan;
@@ -162,6 +176,17 @@
= "android.service.notification.NotificationListenerService";
/**
+ * If this category is declared in the application manifest for a service of this type, this
+ * service will be bound when VR mode is enabled, and unbound when VR mode is disabled rather
+ * than the normal lifecycle for a notification service.
+ *
+ * {@see android.app.Activity#setVrMode(boolean)}
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.INTENT_CATEGORY)
+ public static final String CATEGORY_VR_NOTIFICATIONS =
+ "android.intent.category.vr.notifications";
+
+ /**
* Implement this method to learn about new notifications as they are posted by apps.
*
* @param sbn A data structure encapsulating the original {@link android.app.Notification}
@@ -270,7 +295,8 @@
// optional
}
- private final INotificationManager getNotificationInterface() {
+ /** @hide */
+ protected final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -613,12 +639,13 @@
@Override
public IBinder onBind(Intent intent) {
if (mWrapper == null) {
- mWrapper = new INotificationListenerWrapper();
+ mWrapper = new NotificationListenerWrapper();
}
return mWrapper;
}
- private boolean isBound() {
+ /** @hide */
+ protected boolean isBound() {
if (mWrapper == null) {
Log.w(TAG, "Notification listener service not yet bound.");
return false;
@@ -643,7 +670,7 @@
int currentUser) throws RemoteException {
mSystemContext = context;
if (mWrapper == null) {
- mWrapper = new INotificationListenerWrapper();
+ mWrapper = new NotificationListenerWrapper();
}
INotificationManager noMan = getNotificationInterface();
noMan.registerListener(mWrapper, componentName, currentUser);
@@ -695,7 +722,8 @@
}
}
- private class INotificationListenerWrapper extends INotificationListener.Stub {
+ /** @hide */
+ protected class NotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
@@ -796,6 +824,35 @@
Log.w(TAG, "Error running onInterruptionFilterChanged", t);
}
}
+
+ @Override
+ public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
+ int importance, boolean user) throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationClick(String key, long time) throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationActionClick(String key, long time, int actionIndex)
+ throws RemoteException {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationRemovedReason(String key, long time, int reason)
+ throws RemoteException {
+ // no-op in the listener
+ }
}
private void applyUpdate(NotificationRankingUpdate update) {
@@ -906,7 +963,8 @@
/**
* Returns the type(s) of visual effects that should be suppressed for this notification.
- * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}.
+ * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK},
+ * {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
*/
public int getSuppressedVisualEffects() {
return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 541623d..4688843 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -79,6 +79,7 @@
private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
private static final boolean DEFAULT_ALLOW_PEEK = true;
private static final boolean DEFAULT_ALLOW_LIGHTS = true;
+ private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
private static final int XML_VERSION = 2;
private static final String ZEN_TAG = "zen";
@@ -95,6 +96,7 @@
private static final String ALLOW_ATT_EVENTS = "events";
private static final String ALLOW_ATT_PEEK = "peek";
private static final String ALLOW_ATT_LIGHTS = "lights";
+ private static final String ALLOW_ATT_SCREEN_ON = "screen_on";
private static final String CONDITION_TAG = "condition";
private static final String CONDITION_ATT_COMPONENT = "component";
@@ -128,6 +130,7 @@
public int user = UserHandle.USER_SYSTEM;
public boolean allowPeek = DEFAULT_ALLOW_PEEK;
public boolean allowLights = DEFAULT_ALLOW_LIGHTS;
+ public boolean allowScreenOn = DEFAULT_ALLOW_SCREEN_ON;
public ZenRule manualRule;
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -156,6 +159,7 @@
}
allowPeek = source.readInt() == 1;
allowLights = source.readInt() == 1;
+ allowScreenOn = source.readInt() == 1;
}
@Override
@@ -185,6 +189,7 @@
}
dest.writeInt(allowPeek ? 1 : 0);
dest.writeInt(allowLights ? 1 : 0);
+ dest.writeInt(allowScreenOn ? 1 : 0);
}
@Override
@@ -200,6 +205,7 @@
.append(",allowEvents=").append(allowEvents)
.append(",allowPeek=").append(allowPeek)
.append(",allowLights=").append(allowLights)
+ .append(",allowScreenOn=").append(allowScreenOn)
.append(",automaticRules=").append(automaticRules)
.append(",manualRule=").append(manualRule)
.append(']').toString();
@@ -240,6 +246,9 @@
if (allowLights != to.allowLights) {
d.addLine("allowLights", allowLights, to.allowLights);
}
+ if (allowScreenOn != to.allowScreenOn) {
+ d.addLine("allowScreenOn", allowScreenOn, to.allowScreenOn);
+ }
final ArraySet<String> allRules = new ArraySet<>();
addKeys(allRules, automaticRules);
addKeys(allRules, to.automaticRules);
@@ -339,6 +348,7 @@
&& other.allowEvents == allowEvents
&& other.allowPeek == allowPeek
&& other.allowLights == allowLights
+ && other.allowScreenOn == allowScreenOn
&& other.user == user
&& Objects.equals(other.automaticRules, automaticRules)
&& Objects.equals(other.manualRule, manualRule);
@@ -348,7 +358,7 @@
public int hashCode() {
return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights,
- user, automaticRules, manualRule);
+ allowScreenOn, user, automaticRules, manualRule);
}
private static String toDayList(int[] days) {
@@ -435,6 +445,8 @@
}
rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK);
rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS);
+ rt.allowScreenOn =
+ safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
} else if (AUTOMATIC_TAG.equals(tag)) {
@@ -465,6 +477,7 @@
out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek));
out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights));
+ out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowScreenOn));
out.endTag(null, ALLOW_TAG);
if (manualRule != null) {
@@ -643,6 +656,9 @@
if (!allowLights) {
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
}
+ if (!allowScreenOn) {
+ suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+ }
priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -681,6 +697,8 @@
if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0;
allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0;
+ allowScreenOn =
+ (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
}
}
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 7e70501..75da82f 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -24,4 +24,5 @@
interface IQSService {
void updateQsTile(in Tile tile);
void onShowDialog(in Tile tile);
+ void setTileMode(in ComponentName component, int mode);
}
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 63a4c5e..4997f75 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -22,6 +22,7 @@
* @hide
*/
oneway interface IQSTileService {
+ void setQSService(in IQSService service);
void setQSTile(in Tile tile);
void onTileAdded();
void onTileRemoved();
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index a53fc59..6104913 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -37,11 +37,12 @@
private static final String TAG = "Tile";
private ComponentName mComponentName;
- private IQSService mService;
private Icon mIcon;
private CharSequence mLabel;
private CharSequence mContentDescription;
+ private IQSService mService;
+
/**
* @hide
*/
@@ -52,8 +53,14 @@
/**
* @hide
*/
- public Tile(ComponentName componentName, IQSService service) {
+ public Tile(ComponentName componentName) {
mComponentName = componentName;
+ }
+
+ /**
+ * @hide
+ */
+ public void setService(IQSService service) {
mService = service;
}
@@ -65,6 +72,13 @@
}
/**
+ * @hide
+ */
+ public IQSService getQsService() {
+ return mService;
+ }
+
+ /**
* Gets the current icon for the tile.
*/
public Icon getIcon() {
@@ -137,21 +151,8 @@
}
}
- /**
- * @hide
- * Notifies the IQSService that this tile is showing a dialog.
- */
- void onShowDialog() {
- try {
- mService.onShowDialog(this);
- } catch (RemoteException e) {
- Log.e(TAG, "Couldn't onShowDialog");
- }
- }
-
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongInterface(mService);
if (mComponentName != null) {
dest.writeByte((byte) 1);
mComponentName.writeToParcel(dest, flags);
@@ -169,7 +170,6 @@
}
private void readFromParcel(Parcel source) {
- mService = IQSService.Stub.asInterface(source.readStrongBinder());
if (source.readByte() != 0) {
mComponentName = ComponentName.CREATOR.createFromParcel(source);
} else {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index fd2d5b0..9b50ef5 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,8 +15,11 @@
*/
package android.service.quicksettings;
+import android.Manifest;
import android.app.Dialog;
import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
@@ -26,29 +29,29 @@
import android.view.WindowManager;
/**
- * A QSTileService provides the user a tile that can be added to Quick Settings.
+ * A TileService provides the user a tile that can be added to Quick Settings.
* Quick Settings is a space provided that allows the user to change settings and
* take quick actions without leaving the context of their current app.
*
- * <p>The lifecycle of a QSTileService is different from some other services in
+ * <p>The lifecycle of a TileService is different from some other services in
* that it may be unbound during parts of its lifecycle. Any of the following
* lifecycle events can happen indepently in a separate binding/creation of the
* service.</p>
*
* <ul>
- * <li>When a tile is added by the user its QSTileService will be bound to and
+ * <li>When a tile is added by the user its TileService will be bound to and
* {@link #onTileAdded()} will be called.</li>
*
* <li>When a tile should be up to date and listing will be indicated by
* {@link #onStartListening()} and {@link #onStopListening()}.</li>
*
- * <li>When the user removes a tile from Quick Settings {@link #onStopListening()}
+ * <li>When the user removes a tile from Quick Settings {@link #onTileRemoved()}
* will be called.</li>
* </ul>
- * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
+ * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
* and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE".
* The label and icon for the service will be used as the default label and
- * icon for the tile. Here is an example QSTileService declaration.</p>
+ * icon for the tile. Here is an example TileService declaration.</p>
* <pre class="prettyprint">
* {@literal
* <service
@@ -67,15 +70,61 @@
public class TileService extends Service {
/**
- * Action that identifies a Service as being a QSTileService.
+ * Action that identifies a Service as being a TileService.
*/
public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+ /**
+ * The tile mode hasn't been set yet.
+ * @hide
+ */
+ public static final int TILE_MODE_UNSET = 0;
+
+ /**
+ * Constant to be returned by {@link #onTileAdded}.
+ * <p>
+ * Passive mode is the default mode for tiles. The System will tell the tile
+ * when it is most important to update by putting it in the listening state.
+ */
+ public static final int TILE_MODE_PASSIVE = 1;
+
+ /**
+ * Constant to be returned by {@link #onTileAdded}.
+ * <p>
+ * Active mode is for tiles which already listen and keep track of their state in their
+ * own process. These tiles may request to send an update to the System while their process
+ * is alive using {@link #requestListeningState}. The System will only bind these tiles
+ * on its own when a click needs to occur.
+ */
+ public static final int TILE_MODE_ACTIVE = 2;
+
+ /**
+ * Used to notify SysUI that Listening has be requested.
+ * @hide
+ */
+ public static final String ACTION_REQUEST_LISTENING
+ = "android.service.quicksettings.action.REQUEST_LISTENING";
+
+ /**
+ * @hide
+ */
+ public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+
private final H mHandler = new H(Looper.getMainLooper());
private boolean mListening = false;
private Tile mTile;
private IBinder mToken;
+ private IQSService mService;
+
+ @Override
+ public void onDestroy() {
+ if (mListening) {
+ onStopListening();
+ mListening = false;
+ }
+ super.onDestroy();
+ }
/**
* Called when the user adds this tile to Quick Settings.
@@ -83,8 +132,12 @@
* Note that this is not guaranteed to be called between {@link #onCreate()}
* and {@link #onStartListening()}, it will only be called when the tile is added
* and not on subsequent binds.
+ *
+ * @see #TILE_MODE_PASSIVE
+ * @see #TILE_MODE_ACTIVE
*/
- public void onTileAdded() {
+ public int onTileAdded() {
+ return TILE_MODE_PASSIVE;
}
/**
@@ -129,7 +182,10 @@
dialog.getWindow().getAttributes().token = mToken;
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_QS_DIALOG);
dialog.show();
- getQsTile().onShowDialog();
+ try {
+ mService.onShowDialog(mTile);
+ } catch (RemoteException e) {
+ }
}
/**
@@ -147,6 +203,11 @@
public IBinder onBind(Intent intent) {
return new IQSTileService.Stub() {
@Override
+ public void setQSService(IQSService service) throws RemoteException {
+ mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget();
+ }
+
+ @Override
public void setQSTile(Tile tile) throws RemoteException {
mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget();
}
@@ -185,6 +246,7 @@
private static final int MSG_TILE_ADDED = 4;
private static final int MSG_TILE_REMOVED = 5;
private static final int MSG_TILE_CLICKED = 6;
+ private static final int MSG_SET_SERVICE = 7;
public H(Looper looper) {
super(looper);
@@ -193,14 +255,35 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
+ case MSG_SET_SERVICE:
+ mService = (IQSService) msg.obj;
+ if (mTile != null) {
+ mTile.setService(mService);
+ }
+ break;
case MSG_SET_TILE:
mTile = (Tile) msg.obj;
+ if (mService != null && mTile != null) {
+ mTile.setService(mService);
+ }
break;
case MSG_TILE_ADDED:
- TileService.this.onTileRemoved();
+ int mode = TileService.this.onTileAdded();
+ if (mService == null) {
+ return;
+ }
+ try {
+ mService.setTileMode(new ComponentName(TileService.this,
+ TileService.this.getClass()), mode);
+ } catch (RemoteException e) {
+ }
break;
case MSG_TILE_REMOVED:
- TileService.this.onTileAdded();
+ if (mListening) {
+ mListening = false;
+ TileService.this.onStopListening();
+ }
+ TileService.this.onTileRemoved();
break;
case MSG_STOP_LISTENING:
if (mListening) {
@@ -221,4 +304,16 @@
}
}
}
+
+ /**
+ * Requests that a tile be put in the listening state so it can send an update.
+ *
+ * This method is only applicable to tiles that return {@link #TILE_MODE_ACTIVE} from
+ * {@link #onTileAdded()}, and will do nothing otherwise.
+ */
+ public static final void requestListeningState(Context context, ComponentName component) {
+ Intent intent = new Intent(ACTION_REQUEST_LISTENING);
+ intent.putExtra(EXTRA_COMPONENT, component);
+ context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+ }
}
diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java
index d9068dc..44811cb 100644
--- a/core/java/android/text/method/Touch.java
+++ b/core/java/android/text/method/Touch.java
@@ -150,6 +150,7 @@
ds[0].mX = event.getX();
ds[0].mY = event.getY();
+ int nx = widget.getScrollX() + (int) dx;
int ny = widget.getScrollY() + (int) dy;
int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom();
@@ -161,6 +162,8 @@
int oldX = widget.getScrollX();
int oldY = widget.getScrollY();
+ scrollTo(widget, layout, nx, ny);
+
// If we actually scrolled, then cancel the up action.
if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) {
widget.cancelLongPress();
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index c119277..fbd9924 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -218,7 +218,7 @@
ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();
if ((mask & WEB_URLS) != 0) {
- gatherLinks(links, text, Patterns.WEB_URL,
+ gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL,
new String[] { "http://", "https://", "rtsp://" },
sUrlMatchFilter, null);
}
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 1becfb4..f22cde0 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -28,12 +28,6 @@
import java.util.HashSet;
import java.util.Locale;
-// TODO: We don't except too many LocaleLists to exist at the same time, and
-// we need access to the data at native level, so we should pass the data
-// down to the native level, create a map of every list seen there, take a
-// pointer back, and just keep that pointer in the Java-level object, so
-// things could be copied very quickly.
-
/**
* LocaleList is an immutable list of Locales, typically used to keep an
* ordered user preferences for locales.
@@ -219,6 +213,20 @@
}
}
+ private static final String STRING_EN_XA = "en-XA";
+ private static final String STRING_AR_XB = "ar-XB";
+ private static final Locale LOCALE_EN_XA = new Locale("en", "XA");
+ private static final Locale LOCALE_AR_XB = new Locale("ar", "XB");
+ private static final int NUM_PSEUDO_LOCALES = 2;
+
+ private static boolean isPseudoLocale(String locale) {
+ return STRING_EN_XA.equals(locale) || STRING_AR_XB.equals(locale);
+ }
+
+ private static boolean isPseudoLocale(Locale locale) {
+ return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale);
+ }
+
private static int matchScore(Locale supported, Locale desired) {
if (supported.equals(desired)) {
return 1; // return early so we don't do unnecessary computation
@@ -226,6 +234,11 @@
if (!supported.getLanguage().equals(desired.getLanguage())) {
return 0;
}
+ if (isPseudoLocale(supported) || isPseudoLocale(desired)) {
+ // The locales are not the same, but the languages are the same, and one of the locales
+ // is a pseudo-locale. So this is not a match.
+ return 0;
+ }
// There is no match if the two locales use different scripts. This will most imporantly
// take care of traditional vs simplified Chinese.
final String supportedScr = getLikelyScript(supported);
@@ -233,24 +246,26 @@
return supportedScr.equals(desiredScr) ? 1 : 0;
}
- /**
- * Returns the first match in the locale list given an unordered array of supported locales
- * in BCP47 format.
- *
- * If the locale list is empty, null would be returned.
- */
- @Nullable
- public Locale getFirstMatch(String[] supportedLocales) {
+ private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
+
+ private Locale computeFirstMatch(String[] supportedLocales, boolean assumeEnglishIsSupported) {
if (mList.length == 1) { // just one locale, perhaps the most common scenario
return mList[0];
}
if (mList.length == 0) { // empty locale list
return null;
}
- // TODO: Figure out what to if en-XA or ar-XB are in the locale list
int bestIndex = Integer.MAX_VALUE;
- for (String tag : supportedLocales) {
- final Locale supportedLocale = Locale.forLanguageTag(tag);
+ final int numSupportedLocales =
+ supportedLocales.length + (assumeEnglishIsSupported ? 1 : 0);
+ for (int i = 0; i < numSupportedLocales; i++) {
+ final Locale supportedLocale;
+ if (assumeEnglishIsSupported) {
+ // Try English first, so we can return early if it's in the LocaleList
+ supportedLocale = (i == 0) ? EN_LATN : Locale.forLanguageTag(supportedLocales[i-1]);
+ } else {
+ supportedLocale = Locale.forLanguageTag(supportedLocales[i]);
+ }
// We expect the average length of locale lists used for locale resolution to be
// smaller than three, so it's OK to do this as an O(mn) algorithm.
for (int idx = 0; idx < mList.length; idx++) {
@@ -271,6 +286,47 @@
}
}
+ /**
+ * Returns the first match in the locale list given an unordered array of supported locales
+ * in BCP47 format.
+ *
+ * If the locale list is empty, null would be returned.
+ */
+ @Nullable
+ public Locale getFirstMatch(String[] supportedLocales) {
+ return computeFirstMatch(supportedLocales, false /* assume English is not supported */);
+ }
+
+ /**
+ * Same as getFirstMatch(), but with English assumed to be supported, even if it's not.
+ * {@hide}
+ */
+ @Nullable
+ public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
+ return computeFirstMatch(supportedLocales, true /* assume English is supported */);
+ }
+
+ /**
+ * Returns true if the array of locale tags only contains empty locales and pseudolocales.
+ * Assumes that there is no repetition in the input.
+ * {@hide}
+ */
+ public static boolean isPseudoLocalesOnly(String[] supportedLocales) {
+ if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
+ // This is for optimization. Since there's no repetition in the input, if we have more
+ // than the number of pseudo-locales plus one for the empty string, it's guaranteed
+ // that we have some meaninful locale in the list, so the list is not "practically
+ // empty".
+ return false;
+ }
+ for (String locale : supportedLocales) {
+ if (!locale.isEmpty() && !isPseudoLocale(locale)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private final static Object sLock = new Object();
@GuardedBy("sLock")
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index fe41932..544444d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -18,9 +18,11 @@
import com.android.internal.os.RuntimeInit;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.LineBreakBufferedWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.Writer;
import java.net.UnknownHostException;
/**
@@ -126,7 +128,7 @@
* @param tr An exception to log
*/
public static int v(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
}
/**
@@ -147,7 +149,7 @@
* @param tr An exception to log
*/
public static int d(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
}
/**
@@ -168,7 +170,7 @@
* @param tr An exception to log
*/
public static int i(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
}
/**
@@ -189,7 +191,7 @@
* @param tr An exception to log
*/
public static int w(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
}
/**
@@ -219,7 +221,7 @@
* @param tr An exception to log
*/
public static int w(String tag, Throwable tr) {
- return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
}
/**
@@ -240,7 +242,7 @@
* @param tr An exception to log
*/
public static int e(String tag, String msg, Throwable tr) {
- return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
}
/**
@@ -292,8 +294,7 @@
// Only mark this as ERROR, do not use ASSERT since that should be
// reserved for cases where the system is guaranteed to abort.
// The onTerribleFailure call does not always cause a crash.
- int bytes = println_native(logId, ERROR, tag, msg + '\n'
- + getStackTraceString(localStack ? what : tr));
+ int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr);
sWtfHandler.onTerribleFailure(tag, what, system);
return bytes;
}
@@ -365,4 +366,107 @@
/** @hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
+
+ /**
+ * Return the maximum payload the log daemon accepts without truncation.
+ * @return LOGGER_ENTRY_MAX_PAYLOAD.
+ */
+ private static native int logger_entry_max_payload_native();
+
+ /**
+ * Helper function for long messages. Uses the LineBreakBufferedWriter to break
+ * up long messages and stacktraces along newlines, but tries to write in large
+ * chunks. This is to avoid truncation.
+ */
+ private static int printlns(int bufID, int priority, String tag, String msg,
+ Throwable tr) {
+ ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
+ // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
+ // and the length of the tag.
+ // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
+ // is too expensive to compute that ahead of time.
+ int bufferSize = NoPreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base.
+ - 2 // Two terminators.
+ - (tag != null ? tag.length() : 0) // Tag length.
+ - 32; // Some slack.
+ // At least assume you can print *some* characters (tag is not too large).
+ bufferSize = Math.max(bufferSize, 100);
+
+ LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);
+
+ lbbw.println(msg);
+
+ if (tr != null) {
+ // This is to reduce the amount of log spew that apps do in the non-error
+ // condition of the network being unavailable.
+ Throwable t = tr;
+ while (t != null) {
+ if (t instanceof UnknownHostException) {
+ break;
+ }
+ t = t.getCause();
+ }
+ if (t == null) {
+ tr.printStackTrace(lbbw);
+ }
+ }
+
+ lbbw.flush();
+
+ return logWriter.getWritten();
+ }
+
+ /**
+ * NoPreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
+ * a JNI call during logging.
+ */
+ static class NoPreloadHolder {
+ public final static int LOGGER_ENTRY_MAX_PAYLOAD =
+ logger_entry_max_payload_native();
+ }
+
+ /**
+ * Helper class to write to the logcat. Different from LogWriter, this writes
+ * the whole given buffer and does not break along newlines.
+ */
+ private static class ImmediateLogWriter extends Writer {
+
+ private int bufID;
+ private int priority;
+ private String tag;
+
+ private int written = 0;
+
+ /**
+ * Create a writer that immediately writes to the log, using the given
+ * parameters.
+ */
+ public ImmediateLogWriter(int bufID, int priority, String tag) {
+ this.bufID = bufID;
+ this.priority = priority;
+ this.tag = tag;
+ }
+
+ public int getWritten() {
+ return written;
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ // Note: using String here has a bit of overhead as a Java object is created,
+ // but using the char[] directly is not easier, as it needs to be translated
+ // to a C char[] for logging.
+ written += println_native(bufID, priority, tag, new String(cbuf, off, len));
+ }
+
+ @Override
+ public void flush() {
+ // Ignored.
+ }
+
+ @Override
+ public void close() {
+ // Ignored.
+ }
+ }
}
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f17a16c..78d5bcd 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -82,6 +82,10 @@
}
}
+ public long getNativePtr() {
+ return mNativePathData;
+ }
+
/**
* Update the path data to match the source.
* Before calling this, make sure canMorph(target, source) is true.
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 2cc91b9..9f2bcfd 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -109,11 +109,137 @@
+ "|z[amw]))";
/**
- * Good characters for Internationalized Resource Identifiers (IRI).
- * This comprises most common used Unicode characters allowed in IRI
- * as detailed in RFC 3987.
- * Specifically, those two byte Unicode characters are not included.
+ * Regular expression to match all IANA top-level domains.
+ *
+ * List accurate as of 2015/11/24. List taken from:
+ * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py
+ *
+ * @hide
*/
+ static final String IANA_TOP_LEVEL_DOMAINS =
+ "(?:"
+ + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active"
+ + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam"
+ + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates"
+ + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])"
+ + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva"
+ + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black"
+ + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique"
+ + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business"
+ + "|buzz|bzh|b[abdefghijmnorstvwyz])"
+ + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards"
+ + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo"
+ + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco"
+ + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach"
+ + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos"
+ + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses"
+ + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])"
+ + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta"
+ + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount"
+ + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])"
+ + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises"
+ + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed"
+ + "|express|e[cegrstu])"
+ + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film"
+ + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth"
+ + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi"
+ + "|f[ijkmor])"
+ + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving"
+ + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger"
+ + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])"
+ + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings"
+ + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai"
+ + "|h[kmnrtu])"
+ + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute"
+ + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])"
+ + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])"
+ + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])"
+ + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc"
+ + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live"
+ + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])"
+ + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba"
+ + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda"
+ + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar"
+ + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])"
+ + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk"
+ + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])"
+ + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka"
+ + "|otsuka|ovh|om)"
+ + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography"
+ + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing"
+ + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property"
+ + "|protection|pub|p[aefghklmnrstwy])"
+ + "|(?:qpon|quebec|qa)"
+ + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals"
+ + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks"
+ + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])"
+ + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo"
+ + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security"
+ + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski"
+ + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting"
+ + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies"
+ + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])"
+ + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica"
+ + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools"
+ + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])"
+ + "|(?:ubs|university|uno|uol|u[agksyz])"
+ + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin"
+ + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])"
+ + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill"
+ + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])"
+ + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434"
+ + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d"
+ + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431"
+ + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648"
+ + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629"
+ + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646"
+ + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633"
+ + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629"
+ + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646"
+ + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627"
+ + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924"
+ + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4"
+ + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd"
+ + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22"
+ + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c"
+ + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71"
+ + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063"
+ + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c"
+ + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c"
+ + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f"
+ + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc"
+ + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137"
+ + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox"
+ + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g"
+ + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim"
+ + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks"
+ + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a"
+ + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd"
+ + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h"
+ + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s"
+ + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c"
+ + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i"
+ + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d"
+ + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt"
+ + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e"
+ + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab"
+ + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema"
+ + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh"
+ + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c"
+ + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb"
+ + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a"
+ + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o"
+ + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)"
+ + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])"
+ + "|(?:zara|zip|zone|zuerich|z[amw]))";
+
+ /**
+ * Kept for backward compatibility reasons.
+ *
+ * @deprecated Deprecated since it does not include all IRI characters defined in RFC 3987
+ */
+ @Deprecated
public static final String GOOD_IRI_CHAR =
"a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
@@ -125,35 +251,148 @@
+ "|[1-9][0-9]|[0-9]))");
/**
+ * Valid UCS characters defined in RFC 3987.
+ */
+ private static final String UCS_CHAR =
+ "\u00A0-\uD7FF" +
+ "\uF900-\uFDCF" +
+ "\uFDF0-\uFFEF" +
+ "\uD800\uDC00-\uD83F\uDFFD" +
+ "\uD840\uDC00-\uD87F\uDFFD" +
+ "\uD880\uDC00-\uD8BF\uDFFD" +
+ "\uD8C0\uDC00-\uD8FF\uDFFD" +
+ "\uD900\uDC00-\uD93F\uDFFD" +
+ "\uD940\uDC00-\uD97F\uDFFD" +
+ "\uD980\uDC00-\uD9BF\uDFFD" +
+ "\uD9C0\uDC00-\uD9FF\uDFFD" +
+ "\uDA00\uDC00-\uDA3F\uDFFD" +
+ "\uDA40\uDC00-\uDA7F\uDFFD" +
+ "\uDA80\uDC00-\uDABF\uDFFD" +
+ "\uDAC0\uDC00-\uDAFF\uDFFD" +
+ "\uDB00\uDC00-\uDB3F\uDFFD" +
+ "\uDB44\uDC00-\uDB7F\uDFFD";
+
+ /**
+ * Valid characters for IRI label defined in RFC 3987.
+ */
+ private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR;
+
+ /**
+ * Valid characters for IRI TLD defined in RFC 3987.
+ */
+ private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR;
+
+ /**
* RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets.
*/
- private static final String IRI
- = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}";
+ private static final String IRI_LABEL =
+ "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}";
- private static final String GOOD_GTLD_CHAR =
- "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF";
- private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}";
- private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD;
+ /**
+ * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters.
+ */
+ private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w";
+
+ private static final String TLD = "(" + PUNYCODE_TLD + "|" + "[" + TLD_CHAR + "]{2,63}" +")";
+
+ private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD;
public static final Pattern DOMAIN_NAME
= Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")");
+ private static final String PROTOCOL = "(?i:http|https|rtsp):\\/\\/";
+
+ /* A word boundary or end of input. This is to stop foo.sure from matching as foo.su */
+ private static final String WORD_BOUNDARY = "(?:\\b|$|^)";
+
+ private static final String USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+ + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+ + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@";
+
+ private static final String PORT_NUMBER = "\\:\\d{1,5}";
+
+ private static final String PATH_AND_QUERY = "\\/(?:(?:[" + LABEL_CHAR
+ + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus optional query params
+ + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*";
+
/**
* Regular expression pattern to match most part of RFC 3987
- * Internationalized URLs, aka IRIs. Commonly used Unicode characters are
- * added.
+ * Internationalized URLs, aka IRIs.
*/
- public static final Pattern WEB_URL = Pattern.compile(
- "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
- + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
- + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
- + "(?:" + DOMAIN_NAME + ")"
- + "(?:\\:\\d{1,5})?)" // plus option port number
- + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params
- + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
- + "(?:\\b|$)"); // and finally, a word boundary or end of
- // input. This is to stop foo.sure from
- // matching as foo.su
+ public static final Pattern WEB_URL = Pattern.compile("("
+ + "("
+ + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?"
+ + "(?:" + DOMAIN_NAME + ")"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")");
+
+ /**
+ * Regular expression that matches known TLDs and punycode TLDs
+ */
+ private static final String STRICT_TLD = "(?:" +
+ IANA_TOP_LEVEL_DOMAINS + "|" + PUNYCODE_TLD + ")";
+
+ /**
+ * Regular expression that matches host names using {@link #STRICT_TLD}
+ */
+ private static final String STRICT_HOST_NAME = "(?:(?:" + IRI_LABEL + "\\.)+"
+ + STRICT_TLD + ")";
+
+ /**
+ * Regular expression that matches domain names using either {@link #STRICT_HOST_NAME} or
+ * {@link #IP_ADDRESS}
+ */
+ private static final Pattern STRICT_DOMAIN_NAME
+ = Pattern.compile("(?:" + STRICT_HOST_NAME + "|" + IP_ADDRESS + ")");
+
+ /**
+ * Regular expression that matches domain names without a TLD
+ */
+ private static final String RELAXED_DOMAIN_NAME =
+ "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS + ")";
+
+ /**
+ * Regular expression to match strings that do not start with a supported protocol. The TLDs
+ * are expected to be one of the known TLDs.
+ */
+ private static final String WEB_URL_WITHOUT_PROTOCOL = "("
+ + WORD_BOUNDARY
+ + "(?<!:\\/\\/)"
+ + "("
+ + "(?:" + STRICT_DOMAIN_NAME + ")"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(?:" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")";
+
+ /**
+ * Regular expression to match strings that start with a supported protocol. Rules for domain
+ * names and TLDs are more relaxed. TLDs are optional.
+ */
+ private static final String WEB_URL_WITH_PROTOCOL = "("
+ + WORD_BOUNDARY
+ + "(?:"
+ + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")"
+ + "(?:" + RELAXED_DOMAIN_NAME + ")?"
+ + "(?:" + PORT_NUMBER + ")?"
+ + ")"
+ + "(?:" + PATH_AND_QUERY + ")?"
+ + WORD_BOUNDARY
+ + ")";
+
+ /**
+ * Regular expression pattern to match IRIs. If a string starts with http(s):// the expression
+ * tries to match the URL structure with a relaxed rule for TLDs. If the string does not start
+ * with http(s):// the TLDs are expected to be one of the known TLDs.
+ *
+ * @hide
+ */
+ public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
+ "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
public static final Pattern EMAIL_ADDRESS
= Pattern.compile(
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index c2a6a7a..051de8a 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -260,6 +260,12 @@
case R.attr.state_enabled:
sb.append("E ");
break;
+ case R.attr.state_checked:
+ sb.append("C ");
+ break;
+ case R.attr.state_activated:
+ sb.append("A ");
+ break;
}
}
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index ea0873d..4888877 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -104,11 +104,15 @@
@Override
public AssetManager getAssets() {
// Ensure we're returning assets with the correct configuration.
- return getResources().getAssets();
+ return getResourcesInternal().getAssets();
}
@Override
public Resources getResources() {
+ return getResourcesInternal();
+ }
+
+ private Resources getResourcesInternal() {
if (mResources == null) {
if (mOverrideConfiguration == null) {
mResources = super.getResources();
@@ -117,7 +121,6 @@
mResources = resContext.getResources();
}
}
-
return mResources;
}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 34835f4..71db0b5 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -21,6 +21,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.view.IDropPermissions;
+
//TODO: Improve Javadoc
/**
* Represents an event that is sent out by the system at various times during a drag and drop
@@ -128,7 +130,7 @@
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
- DropPermissionHolder mDropPermissionHolder;
+ IDropPermissions mDropPermissions;
Object mLocalState;
boolean mDragResult;
@@ -146,7 +148,7 @@
* Action constant returned by {@link #getAction()}: Signals the start of a
* drag and drop operation. The View should return {@code true} from its
* {@link View#onDragEvent(DragEvent) onDragEvent()} handler method or
- * {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
+ * {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()} listener
* if it can accept a drop. The onDragEvent() or onDrag() methods usually inspect the metadata
* from {@link #getClipDescription()} to determine if they can accept the data contained in
* this drag. For an operation that doesn't represent data transfer, these methods may
@@ -190,7 +192,7 @@
* within the View object's bounding box.
* <p>
* The View should return {@code true} from its {@link View#onDragEvent(DragEvent)}
- * handler or {@link View.View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
+ * handler or {@link View.OnDragListener#onDrag(View,DragEvent) OnDragListener.onDrag()}
* listener if it accepted the drop, and {@code false} if it ignored the drop.
* </p>
* <p>
@@ -255,13 +257,13 @@
}
private void init(int action, float x, float y, ClipDescription description, ClipData data,
- DropPermissionHolder dropPermissionHolder, Object localState, boolean result) {
+ IDropPermissions dropPermissions, Object localState, boolean result) {
mAction = action;
mX = x;
mY = y;
mClipDescription = description;
mClipData = data;
- mDropPermissionHolder = dropPermissionHolder;
+ mDropPermissions = dropPermissions;
mLocalState = localState;
mDragResult = result;
}
@@ -272,13 +274,13 @@
/** @hide */
public static DragEvent obtain(int action, float x, float y, Object localState,
- ClipDescription description, ClipData data, DropPermissionHolder dropPermissionHolder,
+ ClipDescription description, ClipData data, IDropPermissions dropPermissions,
boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
if (gRecyclerTop == null) {
ev = new DragEvent();
- ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
+ ev.init(action, x, y, description, data, dropPermissions, localState, result);
return ev;
}
ev = gRecyclerTop;
@@ -289,7 +291,7 @@
ev.mRecycled = false;
ev.mNext = null;
- ev.init(action, x, y, description, data, dropPermissionHolder, localState, result);
+ ev.init(action, x, y, description, data, dropPermissions, localState, result);
return ev;
}
@@ -297,7 +299,7 @@
/** @hide */
public static DragEvent obtain(DragEvent source) {
return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
- source.mClipDescription, source.mClipData, source.mDropPermissionHolder,
+ source.mClipDescription, source.mClipData, source.mDropPermissions,
source.mDragResult);
}
@@ -362,15 +364,9 @@
return mClipDescription;
}
- /**
- * Returns the {@link android.view.DropPermissionHolder} object that can be used by the drag
- * listener to request and release the permissions for the content URIs contained in the
- * {@link android.content.ClipData} object associated with this event.
- * This method only returns valid data if the event action is {@link #ACTION_DROP}.
- * @return The DropPermissionHolder object used to handle content URI permissions.
- */
- public DropPermissionHolder getDropPermissionHolder() {
- return mDropPermissionHolder;
+ /** @hide */
+ public IDropPermissions getDropPermissions() {
+ return mDropPermissions;
}
/**
@@ -493,11 +489,11 @@
dest.writeInt(1);
mClipDescription.writeToParcel(dest, flags);
}
- if (mDropPermissionHolder == null) {
+ if (mDropPermissions == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
- mDropPermissionHolder.writeToParcel(dest, flags);
+ dest.writeStrongBinder(mDropPermissions.asBinder());
}
}
@@ -519,7 +515,7 @@
event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
}
if (in.readInt() != 0) {
- event.mDropPermissionHolder = DropPermissionHolder.CREATOR.createFromParcel(in);
+ event.mDropPermissions = IDropPermissions.Stub.asInterface(in.readStrongBinder());;
}
return event;
}
diff --git a/core/java/android/view/DropPermissionHolder.java b/core/java/android/view/DropPermissionHolder.java
deleted file mode 100644
index 993e67a..0000000
--- a/core/java/android/view/DropPermissionHolder.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package android.view;
-
-import android.app.IActivityManager;
-import android.content.ClipData;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import com.android.internal.view.IDropPermissionHolder;
-
-import java.util.ArrayList;
-
-public class DropPermissionHolder implements Parcelable {
-
- IDropPermissionHolder mDropPermissionHolder;
-
- /**
- * Create a new DropPermissionHolder to be passed to the client with a DragEvent.
- *
- * @hide
- */
- public DropPermissionHolder(ClipData clipData, IActivityManager activityManager,
- int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
- mDropPermissionHolder = new LocalDropPermissionHolder(clipData, activityManager,
- sourceUid, targetPackage, mode, sourceUserId, targetUserId);
- }
-
- private class LocalDropPermissionHolder extends IDropPermissionHolder.Stub {
-
- private final IActivityManager mActivityManager;
- private final int mSourceUid;
- private final String mTargetPackage;
- private final int mMode;
- private final int mSourceUserId;
- private final int mTargetUserId;
-
- IBinder mPermissionOwner = null;
-
- final private ArrayList<Uri> mUris = new ArrayList<Uri>();
-
- LocalDropPermissionHolder(ClipData clipData, IActivityManager activityManager,
- int sourceUid, String targetPackage, int mode, int sourceUserId, int targetUserId) {
- mActivityManager = activityManager;
- mSourceUid = sourceUid;
- mTargetPackage = targetPackage;
- mMode = mode;
- mSourceUserId = sourceUserId;
- mTargetUserId = targetUserId;
-
- int N = clipData.getItemCount();
- for (int i = 0; i != N; ++i) {
- ClipData.Item item = clipData.getItemAt(i);
-
- if (item.getUri() != null) {
- mUris.add(item.getUri());
- }
-
- Intent intent = item.getIntent();
- if (intent != null && intent.getData() != null) {
- mUris.add(intent.getData());
- }
- }
- }
-
- @Override
- public void grant() throws RemoteException {
- if (mPermissionOwner != null) {
- return;
- }
-
- mPermissionOwner = mActivityManager.newUriPermissionOwner("drop");
-
- long origId = Binder.clearCallingIdentity();
- try {
- for (Uri mUri : mUris) {
- mActivityManager.grantUriPermissionFromOwner(
- mPermissionOwner, mSourceUid, mTargetPackage, mUri, mMode,
- mSourceUserId, mTargetUserId);
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
-
- }
-
- @Override
- public void revoke() throws RemoteException {
- if (mPermissionOwner == null) {
- return;
- }
-
- for (Uri mUri : mUris) {
- mActivityManager.revokeUriPermissionFromOwner(
- mPermissionOwner, mUri, mMode, mSourceUserId);
- }
-
- mPermissionOwner = null;
- }
- }
-
- /**
- * Request permissions granted by the activity which started the drag.
- */
- public void grant() {
- try {
- mDropPermissionHolder.grant();
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Revoke permissions granted by the {@link #grant()} call.
- */
- public void revoke() {
- try {
- mDropPermissionHolder.revoke();
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Returns information about the {@link android.os.Parcel} representation of this
- * DropPermissionHolder object.
- * @return Information about the {@link android.os.Parcel} representation.
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Creates a {@link android.os.Parcel} object from this DropPermissionHolder object.
- * @param dest A {@link android.os.Parcel} object in which to put the DropPermissionHolder
- * object.
- * @param flags Flags to store in the Parcel.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mDropPermissionHolder.asBinder());
- }
-
- DropPermissionHolder(Parcel in) {
- mDropPermissionHolder = IDropPermissionHolder.Stub.asInterface(in.readStrongBinder());
- }
-
- /**
- * A container for creating a DropPermissionHolder from a Parcel.
- */
- public static final Parcelable.Creator<DropPermissionHolder> CREATOR
- = new Parcelable.Creator<DropPermissionHolder>() {
- public DropPermissionHolder createFromParcel(Parcel in) {
- return new DropPermissionHolder(in);
- }
- public DropPermissionHolder[] newArray(int size) {
- return new DropPermissionHolder[size];
- }
- };
-}
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DropPermissions.java
new file mode 100644
index 0000000..8c948a9
--- /dev/null
+++ b/core/java/android/view/DropPermissions.java
@@ -0,0 +1,104 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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.view;
+
+import android.os.IBinder;
+import android.os.RemoteException;
+import com.android.internal.view.IDropPermissions;
+import dalvik.system.CloseGuard;
+
+
+/**
+ * {@link DropPermissions} controls the access permissions for the content URIs associated with a
+ * {@link DragEvent}.
+ * <p>
+ * Permission are granted when this object is created by {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) Activity.requestDropPermissions}.
+ * Which permissions are granted is defined by the set of flags passed to {@link
+ * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
+ * View.startDragAndDrop} by the app that started the drag operation.
+ * <p>
+ * The life cycle of the permissions is bound to the activity used to call {@link
+ * android.app.Activity#requestDropPermissions(DragEvent) requestDropPermissions}. The
+ * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
+ * whichever occurs first.
+ */
+public final class DropPermissions {
+
+ private final IDropPermissions mDropPermissions;
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * Create a new {@link DropPermissions} object to control the access permissions for content
+ * URIs associated with {@link DragEvent}.
+ * @param dragEvent Drag event
+ * @return {@link DropPermissions} object or null if there are no content URIs associated with
+ * the {@link DragEvent}.
+ * @hide
+ */
+ public static DropPermissions obtain(DragEvent dragEvent) {
+ if (dragEvent.getDropPermissions() == null) {
+ return null;
+ }
+ return new DropPermissions(dragEvent.getDropPermissions());
+ }
+
+ /** @hide */
+ private DropPermissions(IDropPermissions dropPermissions) {
+ mDropPermissions = dropPermissions;
+ }
+
+ /**
+ * Take the permissions and bind their lifetime to the activity.
+ * @param activityToken Binder pointing to an Activity instance to bind the lifetime to.
+ * @return True if permissions are successfully taken.
+ * @hide
+ */
+ public boolean take(IBinder activityToken) {
+ try {
+ mDropPermissions.take(activityToken);
+ } catch (RemoteException e) {
+ return false;
+ }
+ mCloseGuard.open("release");
+ return true;
+ }
+
+ /**
+ * Revoke permissions explicitly.
+ */
+ public void release() {
+ try {
+ mDropPermissions.release();
+ } catch (RemoteException e) {
+ }
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ release();
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/core/java/android/view/IDockedStackListener.aidl
similarity index 70%
rename from core/java/android/view/IDockDividerVisibilityListener.aidl
rename to core/java/android/view/IDockedStackListener.aidl
index a7d5cda..77fa7e2 100644
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -22,6 +22,15 @@
*
* @hide
*/
-oneway interface IDockDividerVisibilityListener {
- void onDockDividerVisibilityChanged(boolean visible);
+oneway interface IDockedStackListener {
+
+ /**
+ * Will fire when an app is shown in side by side mode and a divider should be shown.
+ */
+ void onDividerVisibilityChanged(boolean visible);
+
+ /**
+ * Called when the docked stack gets created or removed.
+ */
+ void onDockedStackExistsChanged(boolean exists);
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7a379d50..84d312d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,7 +29,7 @@
import android.os.IRemoteCallback;
import android.view.IApplicationToken;
import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IWindowSession;
@@ -101,11 +101,14 @@
* the task doesn't exist yet.
* @param configuration Configuration that is being used with this task.
* @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+ * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
+ * they are in.
*/
void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack);
+ in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
+ boolean alwaysFocusable);
/**
*
* @param token The token we are adding to the input task Id.
@@ -354,7 +357,17 @@
void setDockedStackResizing(boolean resizing);
/**
- * Registers a listener that will be called when the dock divider changes its visibility.
+ * Registers a listener that will be called when the dock divider changes its visibility or when
+ * the docked stack gets added/removed.
*/
- void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener);
+ void registerDockedStackListener(IDockedStackListener listener);
+
+ /**
+ * Updates the dim layer used while resizing.
+ *
+ * @param visible Whether the dim layer should be visible.
+ * @param targetStackId The id of the task stack the dim layer should be placed on.
+ * @param alpha The translucency of the dim layer, between 0 and 1.
+ */
+ void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 55cf56f..f037958 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1779,6 +1779,7 @@
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_SPACE:
return true;
default:
return false;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aa29636..914bd56 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -555,6 +555,26 @@
}
}
+ private static final ClassLoader BOOT_CLASS_LOADER = LayoutInflater.class.getClassLoader();
+
+ private final boolean verifyClassLoader(Constructor<? extends View> constructor) {
+ final ClassLoader constructorLoader = constructor.getDeclaringClass().getClassLoader();
+ if (constructorLoader == BOOT_CLASS_LOADER) {
+ // fast path for boot class loader (most common case?) - always ok
+ return true;
+ }
+ // in all normal cases (no dynamic code loading), we will exit the following loop on the
+ // first iteration (i.e. when the declaring classloader is the contexts class loader).
+ ClassLoader cl = mContext.getClassLoader();
+ do {
+ if (constructorLoader == cl) {
+ return true;
+ }
+ cl = cl.getParent();
+ } while (cl != null);
+ return false;
+ }
+
/**
* Low-level function for instantiating a view by name. This attempts to
* instantiate a view class of the given <var>name</var> found in this
@@ -575,6 +595,10 @@
public final View createView(String name, String prefix, AttributeSet attrs)
throws ClassNotFoundException, InflateException {
Constructor<? extends View> constructor = sConstructorMap.get(name);
+ if (constructor != null && !verifyClassLoader(constructor)) {
+ constructor = null;
+ sConstructorMap.remove(name);
+ }
Class<? extends View> clazz = null;
try {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0195dec..7a544b8 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -977,6 +977,37 @@
public static final int AXIS_SCROLL = 26;
/**
+ * Axis constant: The movement of x position of a motion event.
+ * <p>
+ * <ul>
+ * <li>For a mouse, reports a difference of x position between the previous position.
+ * This is useful when pointer is captured, in that case the mouse pointer doesn't change
+ * the location but this axis reports the difference which allows the app to see
+ * how the mouse is moved.
+ * </ul>
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int, int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_RELATIVE_X = 27;
+
+ /**
+ * Axis constant: The movement of y position of a motion event.
+ * <p>
+ * This is similar to {@link #AXIS_RELATIVE_X} but for y-axis.
+ * </p>
+ *
+ * @see #getAxisValue(int, int)
+ * @see #getHistoricalAxisValue(int, int, int)
+ * @see MotionEvent.PointerCoords#getAxisValue(int, int)
+ * @see InputDevice#getMotionRange
+ */
+ public static final int AXIS_RELATIVE_Y = 28;
+
+ /**
* Axis constant: Generic 1 axis of a motion event.
* The interpretation of a generic axis is device-specific.
*
@@ -1187,6 +1218,8 @@
names.append(AXIS_DISTANCE, "AXIS_DISTANCE");
names.append(AXIS_TILT, "AXIS_TILT");
names.append(AXIS_SCROLL, "AXIS_SCROLL");
+ names.append(AXIS_RELATIVE_X, "AXIS_REALTIVE_X");
+ names.append(AXIS_RELATIVE_Y, "AXIS_REALTIVE_Y");
names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index aa879cd..7ba046b 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -17,8 +17,6 @@
package android.view;
import android.annotation.NonNull;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.util.SparseArray;
import com.android.internal.util.XmlUtils;
@@ -142,6 +140,9 @@
private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
+ /** @hide */
+ public static boolean sUseLargeIcons = false;
+
private final int mStyle;
private int mSystemIconResourceId;
private Bitmap mBitmap;
@@ -210,10 +211,7 @@
styleIndex = getSystemIconStyleIndex(STYLE_DEFAULT);
}
- int accessibilityConfig = Settings.Secure.getIntForUser(
- context.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
- 0, UserHandle.USER_CURRENT);
- int defStyle = (accessibilityConfig == 1) ?
+ int defStyle = sUseLargeIcons ?
com.android.internal.R.style.LargePointer : com.android.internal.R.style.Pointer;
TypedArray a = context.obtainStyledAttributes(null,
com.android.internal.R.styleable.Pointer,
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 394660f..ef50fdc 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -57,6 +57,7 @@
private static native int nativeGetHeight(long nativeObject);
private static native long nativeGetNextFrameNumber(long nativeObject);
+ private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
public static final Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -95,6 +96,21 @@
private HwuiContext mHwuiContext;
/** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
+ SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
+ public @interface ScalingMode {}
+ // From system/window.h
+ /** @hide */
+ static final int SCALING_MODE_FREEZE = 0;
+ /** @hide */
+ static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
+ /** @hide */
+ static final int SCALING_MODE_SCALE_CROP = 2;
+ /** @hide */
+ static final int SCALING_MODE_NO_SCALE_CROP = 3;
+
+ /** @hide */
@IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
@Retention(RetentionPolicy.SOURCE)
public @interface Rotation {}
@@ -500,6 +516,20 @@
}
/**
+ * Set the scaling mode to be used for this surfaces buffers
+ * @hide
+ */
+ void setScalingMode(@ScalingMode int scalingMode) {
+ synchronized (mLock) {
+ checkNotReleasedLocked();
+ int err = nativeSetScalingMode(mNativeObject, scalingMode);
+ if (err != 0) {
+ throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
+ }
+ }
+ }
+
+ /**
* Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
* when a SurfaceTexture could not successfully be allocated.
*/
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 589c0dc..f4fa980 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -578,8 +578,19 @@
}
mSurface.transferFrom(mNewSurface);
-
if (visible && mSurface.isValid()) {
+ // We set SCALING_MODE_NO_SCALE_CROP to allow the WindowManager
+ // to update our Surface crop without requiring a new buffer from
+ // us. In the default mode of SCALING_MODE_FREEZE, surface geometry
+ // state (which includes crop) is only applied when a buffer
+ // with appropriate geometry is available. During drag resize
+ // it is quite frequent that a matching buffer will not be available
+ // (because we are constantly being resized and have fallen behind).
+ // However in such situations the WindowManager still needs to be able
+ // to update our crop to ensure we stay within the bounds of the containing
+ // window.
+ mSurface.setScalingMode(Surface.SCALING_MODE_NO_SCALE_CROP);
+
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6b60be9..1be4810 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -297,7 +297,7 @@
@Override
public void setForeground(Drawable foreground) {
- if (foreground != null) {
+ if (foreground != null && !sTextureViewIgnoresDrawableSetters) {
throw new UnsupportedOperationException(
"TextureView doesn't support displaying a foreground drawable");
}
@@ -305,7 +305,7 @@
@Override
public void setBackgroundDrawable(Drawable background) {
- if (background != null) {
+ if (background != null && !sTextureViewIgnoresDrawableSetters) {
throw new UnsupportedOperationException(
"TextureView doesn't support displaying a background drawable");
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f2a4d7b..0e4bc84 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -422,9 +422,10 @@
* @return True if the initialization was successful, false otherwise.
*/
boolean initialize(Surface surface) throws OutOfResourcesException {
+ boolean status = !mInitialized;
mInitialized = true;
updateEnabledState(surface);
- boolean status = nInitialize(mNativeProxy, surface);
+ nInitialize(mNativeProxy, surface);
return status;
}
@@ -958,7 +959,7 @@
private static native boolean nLoadSystemProperties(long nativeProxy);
private static native void nSetName(long nativeProxy, String name);
- private static native boolean nInitialize(long nativeProxy, Surface window);
+ private static native void nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
private static native boolean nPauseSurface(long nativeProxy, Surface window);
private static native void nSetup(long nativeProxy, int width, int height,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2368642..68f1ac3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -812,6 +812,12 @@
private static boolean sLayoutParamsAlwaysChanged = false;
/**
+ * Allow setForeground/setBackground to be called (and ignored) on a textureview,
+ * without throwing
+ */
+ static boolean sTextureViewIgnoresDrawableSetters = false;
+
+ /**
* This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
* calling setFlags.
*/
@@ -3586,6 +3592,9 @@
private int[] mDrawableState = null;
+ /** Whether draw() is currently being called. */
+ private boolean mInDraw = false;
+
ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND;
/**
@@ -3984,6 +3993,10 @@
// work. Partial layout breaks this assumption.
sLayoutParamsAlwaysChanged = targetSdkVersion <= M;
+ // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
+ // On N+, we throw, but that breaks compatibility with apps that use these methods.
+ sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+
sCompatibilityDone = true;
}
}
@@ -10162,8 +10175,8 @@
/**
* Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent)
* KeyEvent.Callback.onKeyUp()}: perform clicking of the view
- * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or
- * {@link KeyEvent#KEYCODE_ENTER} is released.
+ * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER}
+ * or {@link KeyEvent#KEYCODE_SPACE} is released.
* <p>Key presses in software keyboards will generally NOT trigger this listener,
* although some may elect to do so in some situations. Do not rely on this to
* catch software key presses.
@@ -12482,8 +12495,7 @@
* Determines whether the given point, in local coordinates is inside the view.
*/
/*package*/ final boolean pointInView(float localX, float localY) {
- return localX >= 0 && localX < (mRight - mLeft)
- && localY >= 0 && localY < (mBottom - mTop);
+ return pointInView(localX, localY, 0);
}
/**
@@ -14716,6 +14728,7 @@
destroyDrawingCache();
cleanupDraw();
+ releasePointerCapture();
mCurrentAnimation = null;
}
@@ -16460,6 +16473,8 @@
*/
@CallSuper
public void draw(Canvas canvas) {
+ mInDraw = true;
+
final int privateFlags = mPrivateFlags;
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE &&
(mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
@@ -16504,6 +16519,7 @@
onDrawForeground(canvas);
// we're done...
+ mInDraw = false;
return;
}
@@ -16651,6 +16667,8 @@
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
+
+ mInDraw = false;
}
/**
@@ -17095,7 +17113,8 @@
*/
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
- if (verifyDrawable(drawable)) {
+ // Don't invalidate if a drawable changes during drawing.
+ if (verifyDrawable(drawable) && !mInDraw) {
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
@@ -21212,6 +21231,56 @@
mPointerIcon = pointerIcon;
}
+ /**
+ * Request capturing further mouse events.
+ *
+ * When the view captures, the mouse pointer icon will disappear and will not change its
+ * position. Further mouse events will come to the capturing view, and the mouse movements
+ * will can be detected through {@link MotionEvent#AXIS_RELATIVE_X} and
+ * {@link MotionEvent#AXIS_RELATIVE_Y}. Non-mouse events (touchscreens, or stylus) will not
+ * be affected.
+ *
+ * The capture will be released through {@link #releasePointerCapture()}, or will be lost
+ * automatically when the view or containing window disappear.
+ *
+ * @return true when succeeds.
+ * @see #releasePointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public void setPointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.setPointerCapture(this);
+ }
+ }
+
+
+ /**
+ * Release the current capture of mouse events.
+ *
+ * If the view does not have the capture, it will do nothing.
+ * @see #setPointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public void releasePointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ viewRootImpl.releasePointerCapture(this);
+ }
+ }
+
+ /**
+ * Checks the capture status of mouse events.
+ *
+ * @return true if the view has the capture.
+ * @see #setPointerCapture()
+ * @see #hasPointerCapture()
+ */
+ public boolean hasPointerCapture() {
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ return (viewRootImpl != null) && viewRootImpl.hasPointerCapture(this);
+ }
+
//
// Properties
//
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cd93dab..1c24392 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1419,8 +1419,9 @@
case DragEvent.ACTION_DRAG_ENDED: {
// Release the bookkeeping now that the drag lifecycle has ended
- if (mChildrenInterestedInDrag != null) {
- for (View child : mChildrenInterestedInDrag) {
+ final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
+ if (childrenInterestedInDrag != null) {
+ for (View child : childrenInterestedInDrag) {
// If a child was interested in the ongoing drag, it's told that it's over
if (child.dispatchDragEvent(event)) {
retval = true;
@@ -1428,12 +1429,11 @@
child.mPrivateFlags2 &= ~View.DRAG_MASK;
child.refreshDrawableState();
}
-
- mChildrenInterestedInDrag.clear();
- if (mCurrentDragStartEvent != null) {
- mCurrentDragStartEvent.recycle();
- mCurrentDragStartEvent = null;
- }
+ childrenInterestedInDrag.clear();
+ }
+ if (mCurrentDragStartEvent != null) {
+ mCurrentDragStartEvent.recycle();
+ mCurrentDragStartEvent = null;
}
if (mIsInterestedInDrag) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index faf2640..0fb3951 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -39,6 +39,7 @@
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
+import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
@@ -174,6 +175,9 @@
View mAccessibilityFocusedHost;
AccessibilityNodeInfo mAccessibilityFocusedVirtualView;
+ // The view which captures mouse input, or null when no one is capturing.
+ View mCapturingView;
+
int mViewVisibility;
boolean mAppVisible = true;
// For recents to freeform transition we need to keep drawing after the app receives information
@@ -197,6 +201,10 @@
// so the window should no longer be active.
boolean mStopped = false;
+ // Set to true if the owner of this window is in ambient mode,
+ // which means it won't receive input events.
+ boolean mIsAmbientMode = false;
+
// Set to true to stop input during an Activity Transition.
boolean mPausedForTransition = false;
@@ -376,6 +384,8 @@
int localChanges;
}
+ private String mTag = TAG;
+
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession();
@@ -502,6 +512,7 @@
mWindowAttributes.packageName = mBasePackageName;
}
attrs = mWindowAttributes;
+ setTag();
// Keep track of the actual window flags supplied by the client.
mClientWindowLayoutFlags = attrs.flags;
@@ -538,7 +549,7 @@
attrs.backup();
mTranslator.translateWindowLayout(attrs);
}
- if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs);
+ if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs);
if (!compatibilityInfo.supportsScreen()) {
attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -599,7 +610,7 @@
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingStableInsets.set(mAttachInfo.mStableInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
- if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
+ if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
mAdded = false;
@@ -693,6 +704,13 @@
}
}
+ private void setTag() {
+ final String[] split = mWindowAttributes.getTitle().toString().split("\\.");
+ if (split.length > 0) {
+ mTag = TAG + "[" + split[split.length - 1] + "]";
+ }
+ }
+
/** Whether the window is in local focus mode or not */
private boolean isInLocalFocusMode() {
return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0;
@@ -982,7 +1000,7 @@
@Override
public ViewParent invalidateChildInParent(int[] location, Rect dirty) {
checkThread();
- if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+ if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty);
if (dirty == null) {
invalidate();
@@ -1032,6 +1050,10 @@
}
}
+ public void setIsAmbientMode(boolean ambient) {
+ mIsAmbientMode = ambient;
+ }
+
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
@@ -1162,7 +1184,7 @@
private boolean collectViewAttributes() {
if (mAttachInfo.mRecomputeGlobalAttributes) {
- //Log.i(TAG, "Computing view hierarchy attributes!");
+ //Log.i(mTag, "Computing view hierarchy attributes!");
mAttachInfo.mRecomputeGlobalAttributes = false;
boolean oldScreenOn = mAttachInfo.mKeepScreenOn;
mAttachInfo.mKeepScreenOn = false;
@@ -1203,7 +1225,7 @@
int childHeightMeasureSpec;
boolean windowSizeMayChange = false;
- if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
+ if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag,
"Measuring " + host + " in display " + desiredWindowWidth
+ "x" + desiredWindowHeight + "...");
@@ -1219,26 +1241,26 @@
if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
baseSize = (int)mTmpValue.getDimension(packageMetrics);
}
- if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
+ if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize);
if (baseSize != 0 && desiredWindowWidth > baseSize) {
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
- if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
+ host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
goodMeasure = true;
} else {
// Didn't fit in that size... try expanding a bit.
baseSize = (baseSize+desiredWindowWidth)/2;
- if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+ if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize="
+ baseSize);
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
- if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured ("
+ host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")");
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
- if (DEBUG_DIALOG) Log.v(TAG, "Good!");
+ if (DEBUG_DIALOG) Log.v(mTag, "Good!");
goodMeasure = true;
}
}
@@ -1338,8 +1360,8 @@
int desiredWindowHeight;
final int viewVisibility = getHostVisibility();
- boolean viewVisibilityChanged = mViewVisibility != viewVisibility
- || mNewSurfaceNeeded;
+ final boolean viewVisibilityChanged = !mFirst
+ && (mViewVisibility != viewVisibility || mNewSurfaceNeeded);
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
@@ -1389,7 +1411,6 @@
mAttachInfo.mHasWindowFocus = false;
mAttachInfo.mWindowVisibility = viewVisibility;
mAttachInfo.mRecomputeGlobalAttributes = false;
- viewVisibilityChanged = false;
mLastConfiguration.setTo(host.getResources().getConfiguration());
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
// Set the layout direction if it has not been set before (inherit is the default)
@@ -1399,14 +1420,13 @@
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
- //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
+ //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
- if (DEBUG_ORIENTATION) Log.v(TAG,
- "View " + host + " resized to: " + frame);
+ if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
mFullRedrawNeeded = true;
mLayoutRequested = true;
windowSizeMayChange = true;
@@ -1459,28 +1479,22 @@
}
if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
- if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+ if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
+ mAttachInfo.mVisibleInsets);
}
if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) {
insetsChanged = true;
}
- if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
- || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ if ((lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
+ || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT)
+ && (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
+ || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD)) {
windowSizeMayChange = true;
-
- if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL
- || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) {
- // NOTE -- system code, won't try to do compat mode.
- Point size = new Point();
- mDisplay.getRealSize(size);
- desiredWindowWidth = size.x;
- desiredWindowHeight = size.y;
- } else {
- DisplayMetrics packageMetrics = res.getDisplayMetrics();
- desiredWindowWidth = packageMetrics.widthPixels;
- desiredWindowHeight = packageMetrics.heightPixels;
- }
+ // NOTE -- system code, won't try to do compat mode.
+ Point size = new Point();
+ mDisplay.getRealSize(size);
+ desiredWindowWidth = size.x;
+ desiredWindowHeight = size.y;
}
}
@@ -1604,7 +1618,7 @@
try {
if (DEBUG_LAYOUT) {
- Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" +
+ Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
host.getMeasuredHeight() + ", params=" + params);
}
@@ -1622,7 +1636,7 @@
final int surfaceGenerationId = mSurface.getGenerationId();
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
- if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString()
+ if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
+ " overscan=" + mPendingOverscanInsets.toShortString()
+ " content=" + mPendingContentInsets.toShortString()
+ " visible=" + mPendingVisibleInsets.toShortString()
@@ -1631,7 +1645,7 @@
+ " surface=" + mSurface);
if (mPendingConfiguration.seq != 0) {
- if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: "
+ if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
+ mPendingConfiguration);
updateConfiguration(new Configuration(mPendingConfiguration), !mFirst);
mPendingConfiguration.seq = 0;
@@ -1650,19 +1664,19 @@
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
if (contentInsetsChanged) {
mAttachInfo.mContentInsets.set(mPendingContentInsets);
- if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
+ if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: "
+ mAttachInfo.mContentInsets);
}
if (overscanInsetsChanged) {
mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets);
- if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: "
+ if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: "
+ mAttachInfo.mOverscanInsets);
// Need to relayout with content insets.
contentInsetsChanged = true;
}
if (stableInsetsChanged) {
mAttachInfo.mStableInsets.set(mPendingStableInsets);
- if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: "
+ if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: "
+ mAttachInfo.mStableInsets);
// Need to relayout with content insets.
contentInsetsChanged = true;
@@ -1679,7 +1693,7 @@
}
if (visibleInsetsChanged) {
mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets);
- if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: "
+ if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: "
+ mAttachInfo.mVisibleInsets);
}
@@ -1860,7 +1874,7 @@
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);
- if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth="
+ if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
@@ -1890,7 +1904,7 @@
}
if (measureAgain) {
- if (DEBUG_LAYOUT) Log.v(TAG,
+ if (DEBUG_LAYOUT) Log.v(mTag,
"And hey let's measure once more: width=" + width
+ " height=" + height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
@@ -2012,15 +2026,15 @@
if (mFirst) {
// handle first focus request
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()="
+ mView.hasFocus());
if (mView != null) {
if (!mView.hasFocus()) {
mView.requestFocus(View.FOCUS_FORWARD);
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view="
+ mView.findFocus());
} else {
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view="
+ mView.findFocus());
}
}
@@ -2092,11 +2106,11 @@
}
private void handleOutOfResourcesException(Surface.OutOfResourcesException e) {
- Log.e(TAG, "OutOfResourcesException initializing HW surface", e);
+ Log.e(mTag, "OutOfResourcesException initializing HW surface", e);
try {
if (!mWindowSession.outOfMemory(mWindow) &&
Process.myUid() != Process.SYSTEM_UID) {
- Slog.w(TAG, "No processes killed for memory; killing self");
+ Slog.w(mTag, "No processes killed for memory; killing self");
Process.killProcess(Process.myPid());
}
} catch (RemoteException ex) {
@@ -2172,7 +2186,7 @@
final View host = mView;
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
- Log.v(TAG, "Laying out " + host + " to (" +
+ Log.v(mTag, "Laying out " + host + " to (" +
host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
}
@@ -2415,11 +2429,11 @@
String thisHash = Integer.toHexString(System.identityHashCode(this));
long frameTime = nowTime - mFpsPrevTime;
long totalTime = nowTime - mFpsStartTime;
- Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime);
+ Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime);
mFpsPrevTime = nowTime;
if (totalTime > 1000) {
float fps = (float) mFpsNumFrames * 1000 / totalTime;
- Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps);
+ Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps);
mFpsStartTime = nowTime;
mFpsNumFrames = 0;
}
@@ -2461,7 +2475,7 @@
try {
mWindowDrawCountDown.await();
} catch (InterruptedException e) {
- Log.e(TAG, "Window redraw count down interruped!");
+ Log.e(mTag, "Window redraw count down interruped!");
}
mWindowDrawCountDown = null;
}
@@ -2471,7 +2485,7 @@
}
if (LOCAL_LOGV) {
- Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
+ Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle());
}
if (mSurfaceHolder != null && mSurface.isValid()) {
mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder);
@@ -2554,7 +2568,7 @@
}
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
- Log.v(TAG, "Draw " + mView + "/"
+ Log.v(mTag, "Draw " + mView + "/"
+ mWindowAttributes.getTitle()
+ ": dirty={" + dirty.left + "," + dirty.top
+ "," + dirty.right + "," + dirty.bottom + "} surface="
@@ -2688,7 +2702,7 @@
handleOutOfResourcesException(e);
return false;
} catch (IllegalArgumentException e) {
- Log.e(TAG, "Could not lock surface", e);
+ Log.e(mTag, "Could not lock surface", e);
// Don't assume this is due to out of memory, it could be
// something else, and if it is something else then we could
// kill stuff (or ourself) for no reason.
@@ -2698,7 +2712,7 @@
try {
if (DEBUG_ORIENTATION || DEBUG_DRAW) {
- Log.v(TAG, "Surface " + surface + " drawing to bitmap w="
+ Log.v(mTag, "Surface " + surface + " drawing to bitmap w="
+ canvas.getWidth() + ", h=" + canvas.getHeight());
//canvas.drawARGB(255, 255, 0, 0);
}
@@ -2721,7 +2735,7 @@
if (DEBUG_DRAW) {
Context cxt = mView.getContext();
- Log.i(TAG, "Drawing: package:" + cxt.getPackageName() +
+ Log.i(mTag, "Drawing: package:" + cxt.getPackageName() +
", metrics=" + cxt.getResources().getDisplayMetrics() +
", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo());
}
@@ -2746,14 +2760,14 @@
try {
surface.unlockCanvasAndPost(canvas);
} catch (IllegalArgumentException e) {
- Log.e(TAG, "Could not unlock surface", e);
+ Log.e(mTag, "Could not unlock surface", e);
mLayoutRequested = true; // ask wm for a new surface next time.
//noinspection ReturnInsideFinallyBlock
return false;
}
if (LOCAL_LOGV) {
- Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
+ Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
}
}
return true;
@@ -2858,14 +2872,14 @@
// view is visible.
rectangle = null;
}
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus
+ " rectangle=" + rectangle + " ci=" + ci
+ " vi=" + vi);
if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) {
// Optimization: if the focus hasn't changed since last
// time, and no layout has happened, then just leave things
// as they are.
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y="
+ mScrollY + " vi=" + vi.toShortString());
} else {
// We need to determine if the currently focused view is
@@ -2873,51 +2887,51 @@
// a pan so it can be seen.
mLastScrolledFocus = new WeakReference<View>(focus);
mScrollMayChange = false;
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?");
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?");
// Try to find the rectangle from the focus view.
if (focus.getGlobalVisibleRect(mVisRect, null)) {
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w="
+ mView.getWidth() + " h=" + mView.getHeight()
+ " ci=" + ci.toShortString()
+ " vi=" + vi.toShortString());
if (rectangle == null) {
focus.getFocusedRect(mTempRect);
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus
+ ": focusRect=" + mTempRect.toShortString());
if (mView instanceof ViewGroup) {
((ViewGroup) mView).offsetDescendantRectToMyCoords(
focus, mTempRect);
}
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Focus in window: focusRect="
+ mTempRect.toShortString()
+ " visRect=" + mVisRect.toShortString());
} else {
mTempRect.set(rectangle);
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Request scroll to rect: "
+ mTempRect.toShortString()
+ " visRect=" + mVisRect.toShortString());
}
if (mTempRect.intersect(mVisRect)) {
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Focus window visible rect: "
+ mTempRect.toShortString());
if (mTempRect.height() >
(mView.getHeight()-vi.top-vi.bottom)) {
// If the focus simply is not going to fit, then
// best is probably just to leave things as-is.
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Too tall; leaving scrollY=" + scrollY);
} else if ((mTempRect.top-scrollY) < vi.top) {
scrollY -= vi.top - (mTempRect.top-scrollY);
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Top covered; scrollY=" + scrollY);
} else if ((mTempRect.bottom-scrollY)
> (mView.getHeight()-vi.bottom)) {
scrollY += (mTempRect.bottom-scrollY)
- (mView.getHeight()-vi.bottom);
- if (DEBUG_INPUT_RESIZE) Log.v(TAG,
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag,
"Bottom covered; scrollY=" + scrollY);
}
handled = true;
@@ -2927,7 +2941,7 @@
}
if (scrollY != mScrollY) {
- if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+ if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old="
+ mScrollY + " , new=" + scrollY);
if (!immediate) {
if (mScroller == null) {
@@ -3004,10 +3018,35 @@
}
}
+ void setPointerCapture(View view) {
+ if (!mAttachInfo.mHasWindowFocus) {
+ Log.w(mTag, "Can't set capture if it's not focused.");
+ return;
+ }
+ if (mCapturingView == view) {
+ return;
+ }
+ mCapturingView = view;
+ InputManager.getInstance().setPointerIconDetached(true);
+ }
+
+ void releasePointerCapture(View view) {
+ if (mCapturingView != view || mCapturingView == null) {
+ return;
+ }
+
+ mCapturingView = null;
+ InputManager.getInstance().setPointerIconDetached(false);
+ }
+
+ boolean hasPointerCapture(View view) {
+ return view != null && mCapturingView == view;
+ }
+
@Override
public void requestChildFocus(View child, View focused) {
if (DEBUG_INPUT_RESIZE) {
- Log.v(TAG, "Request child focus: focus now " + focused);
+ Log.v(mTag, "Request child focus: focus now " + focused);
}
checkThread();
scheduleTraversals();
@@ -3016,7 +3055,7 @@
@Override
public void clearChildFocus(View child) {
if (DEBUG_INPUT_RESIZE) {
- Log.v(TAG, "Clearing child focus");
+ Log.v(mTag, "Clearing child focus");
}
checkThread();
scheduleTraversals();
@@ -3081,6 +3120,10 @@
mView = null;
mAttachInfo.mRootView = null;
+ if (mCapturingView != null) {
+ releasePointerCapture(mCapturingView);
+ }
+
mSurface.release();
if (mInputQueueCallback != null && mInputQueue != null) {
@@ -3111,7 +3154,7 @@
}
void updateConfiguration(Configuration config, boolean force) {
- if (DEBUG_CONFIGURATION) Log.v(TAG,
+ if (DEBUG_CONFIGURATION) Log.v(mTag,
"Applying new config to window "
+ mWindowAttributes.getTitle()
+ ": " + config);
@@ -3274,6 +3317,7 @@
&& mPendingStableInsets.equals(args.arg6)
&& mPendingVisibleInsets.equals(args.arg3)
&& mPendingOutsets.equals(args.arg7)
+ && mPendingBackDropFrame.equals(args.arg8)
&& args.arg4 == null) {
break;
}
@@ -3346,10 +3390,10 @@
mAttachInfo.mHardwareRenderer.initializeIfNeeded(
mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets);
} catch (OutOfResourcesException e) {
- Log.e(TAG, "OutOfResourcesException locking surface", e);
+ Log.e(mTag, "OutOfResourcesException locking surface", e);
try {
if (!mWindowSession.outOfMemory(mWindow)) {
- Slog.w(TAG, "No processes killed for memory; killing self");
+ Slog.w(mTag, "No processes killed for memory; killing self");
Process.killProcess(Process.myPid());
}
} catch (RemoteException ex) {
@@ -3390,6 +3434,8 @@
.softInputMode &=
~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
mHasHadWindowFocus = true;
+ } else if (mCapturingView != null) {
+ releasePointerCapture(mCapturingView);
}
}
} break;
@@ -3670,7 +3716,7 @@
*/
protected void onDeliverToNext(QueuedInputEvent q) {
if (DEBUG_INPUT_STAGES) {
- Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q);
+ Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q);
}
if (mNext != null) {
mNext.deliver(q);
@@ -3681,23 +3727,23 @@
protected boolean shouldDropInputEvent(QueuedInputEvent q) {
if (mView == null || !mAdded) {
- Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent);
+ Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
return true;
} else if ((!mAttachInfo.mHasWindowFocus
&& !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
- || (mPausedForTransition && !isBack(q.mEvent))) {
+ || mIsAmbientMode || (mPausedForTransition && !isBack(q.mEvent))) {
// This is a focus event and the window doesn't currently have input focus or
// has stopped. This could be an event that came back from the previous stage
// but the window has lost focus or stopped in the meantime.
if (isTerminalInputEvent(q.mEvent)) {
// Don't drop terminal input events, however mark them as canceled.
q.mEvent.cancel();
- Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent);
+ Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent);
return false;
}
// Drop non-terminal input events.
- Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent);
+ Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent);
return true;
}
return false;
@@ -3937,7 +3983,7 @@
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
final InputEvent event = q.mEvent;
- if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event);
+ if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event);
int result = imm.dispatchInputEvent(event, q, this, mHandler);
if (result == InputMethodManager.DISPATCH_HANDLED) {
return FINISH_HANDLED;
@@ -4236,7 +4282,10 @@
}
mAttachInfo.mUnbufferedDispatchRequested = false;
- boolean handled = mView.dispatchPointerEvent(event);
+ final View eventTarget =
+ (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
+ mCapturingView : mView;
+ boolean handled = eventTarget.dispatchPointerEvent(event);
if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
mUnbufferedInputDispatch = true;
if (mConsumeBatchedInputScheduled) {
@@ -4366,7 +4415,7 @@
break;
}
- if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step="
+ if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step="
+ mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration
+ " move=" + event.getX()
+ " / Y=" + mY.position + " step="
@@ -4405,11 +4454,11 @@
if (keycode != 0) {
if (movement < 0) movement = -movement;
int accelMovement = (int)(movement * accel);
- if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement
+ if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement
+ " accelMovement=" + accelMovement
+ " accel=" + accel);
if (accelMovement > movement) {
- if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+ if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
+ keycode);
movement--;
int repeatCount = accelMovement - movement;
@@ -4419,7 +4468,7 @@
InputDevice.SOURCE_KEYBOARD));
}
while (movement > 0) {
- if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: "
+ if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: "
+ keycode);
movement--;
curTime = SystemClock.uptimeMillis();
@@ -4661,7 +4710,7 @@
update(event, true);
break;
default:
- Log.w(TAG, "Unexpected action: " + event.getActionMasked());
+ Log.w(mTag, "Unexpected action: " + event.getActionMasked());
}
}
@@ -5300,7 +5349,7 @@
mWindowSession.dragRecipientEntered(mWindow);
}
} catch (RemoteException e) {
- Slog.e(TAG, "Unable to note drag target change");
+ Slog.e(mTag, "Unable to note drag target change");
}
}
@@ -5308,10 +5357,10 @@
if (what == DragEvent.ACTION_DROP) {
mDragDescription = null;
try {
- Log.i(TAG, "Reporting drop result: " + result);
+ Log.i(mTag, "Reporting drop result: " + result);
mWindowSession.reportDropResult(mWindow, result);
} catch (RemoteException e) {
- Log.e(TAG, "Unable to report drop result");
+ Log.e(mTag, "Unable to report drop result");
}
}
@@ -5397,14 +5446,14 @@
mTranslator.translateWindowLayout(params);
}
if (params != null) {
- if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params);
+ if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
}
mPendingConfiguration.seq = 0;
- //Log.d(TAG, ">>>>>> CALLING relayout");
+ //Log.d(mTag, ">>>>>> CALLING relayout");
if (params != null && mOrigWindowType != params.type) {
// For compatibility with old apps, don't crash here.
if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
- Slog.w(TAG, "Window type can not be changed after "
+ Slog.w(mTag, "Window type can not be changed after "
+ "the window is added; ignoring change of " + mView);
params.type = mOrigWindowType;
}
@@ -5416,7 +5465,7 @@
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
- //Log.d(TAG, "<<<<<< BACK FROM relayout");
+ //Log.d(mTag, "<<<<<< BACK FROM relayout");
if (restore) {
params.restore();
}
@@ -5463,7 +5512,7 @@
}
} catch (IllegalStateException e) {
// Exception thrown by getAudioManager() when mView is null
- Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e);
+ Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e);
e.printStackTrace();
}
}
@@ -5511,6 +5560,8 @@
writer.println(mProcessInputEventsScheduled);
writer.print(innerPrefix); writer.print("mTraversalScheduled=");
writer.print(mTraversalScheduled);
+ writer.print(innerPrefix); writer.print("mIsAmbientMode=");
+ writer.print(mIsAmbientMode);
if (mTraversalScheduled) {
writer.print(" (barrier="); writer.print(mTraversalBarrier); writer.println(")");
} else {
@@ -5584,7 +5635,7 @@
if (!mIsDrawing) {
destroyHardwareRenderer();
} else {
- Log.e(TAG, "Attempting to destroy the window while drawing!\n" +
+ Log.e(mTag, "Attempting to destroy the window while drawing!\n" +
" window=" + this + ", title=" + mWindowAttributes.getTitle());
}
mHandler.sendEmptyMessage(MSG_DIE);
@@ -5593,7 +5644,7 @@
void doDie() {
checkThread();
- if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface);
+ if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface);
synchronized (this) {
if (mRemoved) {
return;
@@ -5686,7 +5737,7 @@
public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
Configuration newConfig, Rect backDropFrame) {
- if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString()
+ if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString()
+ " contentInsets=" + contentInsets.toShortString()
+ " visibleInsets=" + visibleInsets.toShortString()
+ " reportDraw=" + reportDraw
@@ -5724,7 +5775,7 @@
}
public void dispatchMoved(int newX, int newY) {
- if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
+ if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
if (mTranslator != null) {
PointF point = new PointF(newX, newY);
mTranslator.translatePointInScreenToAppWindow(point);
@@ -6641,7 +6692,7 @@
}
void changeCanvasOpacity(boolean opaque) {
- Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
+ Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque);
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.setOpaque(opaque);
}
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 53490b4..d7a98ab 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2106,4 +2106,10 @@
* to better match your application.
*/
public abstract void setResizingCaptionDrawable(Drawable drawable);
+
+ /**
+ * Called when the activity changes from fullscreen mode to multi-window mode and visa-versa.
+ * @hide
+ */
+ public abstract void onMultiWindowModeChanged();
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2e884cc..251f4c8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1183,6 +1183,13 @@
public static final int PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH = 0x00008000;
/**
+ * Flag to indicate that this child window should always be laid-out in the parent
+ * frame regardless of the current windowing mode configuration.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME = 0x00010000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 01d1566..6aa5e2f 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -134,6 +134,25 @@
private static String TAG_SIGNATURE = "signature";
/**
+ * Reads all signatures at the current depth (within the current provider) from the XML parser.
+ */
+ private static String[] readSignatures(XmlResourceParser parser) throws IOException,
+ XmlPullParserException {
+ List<String> signatures = new ArrayList<String>();
+ int outerDepth = parser.getDepth();
+ while(XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals(TAG_SIGNATURE)) {
+ // Parse the value within the signature tag
+ String signature = parser.nextText();
+ signatures.add(signature);
+ } else {
+ Log.e(LOGTAG, "Found an element in a webview provider that is not a signature");
+ }
+ }
+ return signatures.toArray(new String[signatures.size()]);
+ }
+
+ /**
* Returns all packages declared in the framework resources as potential WebView providers.
* @hide
* */
@@ -161,9 +180,9 @@
throw new MissingWebViewPackageException(
"WebView provider in framework resources missing description");
}
- String signature = parser.getAttributeValue(null, TAG_SIGNATURE);
webViewProviders.add(
- new WebViewProviderInfo(packageName, description, signature));
+ new WebViewProviderInfo(packageName, description,
+ readSignatures(parser)));
}
else {
Log.e(LOGTAG, "Found an element that is not a webview provider");
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index d5e3a230..7bad652 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -40,10 +40,10 @@
public WebViewPackageNotFoundException(Exception e) { super(e); }
}
- public WebViewProviderInfo(String packageName, String description, String signature) {
+ public WebViewProviderInfo(String packageName, String description, String[] signatures) {
this.packageName = packageName;
this.description = description;
- this.signature = signature;
+ this.signatures = signatures;
}
private boolean hasValidSignature() {
@@ -53,7 +53,7 @@
try {
// If no signature is declared, instead check whether the package is included in the
// system.
- if (signature == null)
+ if (signatures == null || signatures.length == 0)
return getPackageInfo().applicationInfo.isSystemApp();
packageSignatures = getPackageInfo().signatures;
@@ -62,8 +62,15 @@
}
if (packageSignatures.length != 1)
return false;
- final byte[] releaseSignature = Base64.decode(signature, Base64.DEFAULT);
- return Arrays.equals(releaseSignature, packageSignatures[0].toByteArray());
+
+ final byte[] packageSignature = packageSignatures[0].toByteArray();
+ // Return whether the package signature matches any of the valid signatures
+ for (String signature : signatures) {
+ final byte[] validSignature = Base64.decode(signature, Base64.DEFAULT);
+ if (Arrays.equals(packageSignature, validSignature))
+ return true;
+ }
+ return false;
}
/**
@@ -109,7 +116,7 @@
private WebViewProviderInfo(Parcel in) {
packageName = in.readString();
description = in.readString();
- signature = in.readString();
+ signatures = in.createStringArray();
packageInfo = null;
}
@@ -122,14 +129,14 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(packageName);
out.writeString(description);
- out.writeString(signature);
+ out.writeStringArray(signatures);
}
// fields read from framework resource
public String packageName;
public String description;
- private String signature;
+ private String[] signatures;
private PackageInfo packageInfo;
// flags declaring we want extra info from the package manager
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 0032f17..48d1d2b 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -20,6 +20,8 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -134,7 +136,7 @@
}
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
super.initForMenu(context, menu);
final Resources res = context.getResources();
@@ -629,8 +631,16 @@
}
public boolean flagActionItems() {
- final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
- final int itemsSize = visibleItems.size();
+ final ArrayList<MenuItemImpl> visibleItems;
+ final int itemsSize;
+ if (mMenu != null) {
+ visibleItems = mMenu.getVisibleItems();
+ itemsSize = visibleItems.size();
+ } else {
+ visibleItems = null;
+ itemsSize = 0;
+ }
+
int maxActions = mMaxItems;
int widthLimit = mActionItemWidthLimit;
final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
@@ -786,7 +796,7 @@
if (isVisible) {
// Not a submenu, but treat it like one.
super.onSubMenuSelected(null);
- } else {
+ } else if (mMenu != null) {
mMenu.close(false /* closeAllMenus */);
}
}
@@ -938,7 +948,9 @@
@Override
protected void onDismiss() {
- mMenu.close();
+ if (mMenu != null) {
+ mMenu.close();
+ }
mOverflowPopup = null;
super.onDismiss();
@@ -999,7 +1011,9 @@
}
public void run() {
- mMenu.changeMenuMode();
+ if (mMenu != null) {
+ mMenu.changeMenuMode();
+ }
final View menuView = (View) mMenuView;
if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
mOverflowPopup = mPopup;
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 1f02c3b..4d0a1c8 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -622,7 +622,7 @@
}
/** @hide */
- public void initialize(MenuBuilder menu) {
+ public void initialize(@Nullable MenuBuilder menu) {
mMenu = menu;
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2d1f855..15cea77 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -72,6 +72,7 @@
import android.util.SparseArray;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
+import android.view.ContextMenu;
import android.view.DisplayListCanvas;
import android.view.DragEvent;
import android.view.Gravity;
@@ -135,13 +136,16 @@
// Tag used when the Editor maintains its own separate UndoManager.
private static final String UNDO_OWNER_TAG = "Editor";
- // Ordering constants used to place the Action Mode items in their menu.
- private static final int MENU_ITEM_ORDER_CUT = 1;
- private static final int MENU_ITEM_ORDER_COPY = 2;
- private static final int MENU_ITEM_ORDER_PASTE = 3;
- private static final int MENU_ITEM_ORDER_SHARE = 4;
- private static final int MENU_ITEM_ORDER_SELECT_ALL = 5;
- private static final int MENU_ITEM_ORDER_REPLACE = 6;
+ // Ordering constants used to place the Action Mode or context menu items in their menu.
+ private static final int MENU_ITEM_ORDER_UNDO = 1;
+ private static final int MENU_ITEM_ORDER_REDO = 2;
+ private static final int MENU_ITEM_ORDER_CUT = 3;
+ private static final int MENU_ITEM_ORDER_COPY = 4;
+ private static final int MENU_ITEM_ORDER_PASTE = 5;
+ private static final int MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT = 6;
+ private static final int MENU_ITEM_ORDER_SHARE = 7;
+ private static final int MENU_ITEM_ORDER_SELECT_ALL = 8;
+ private static final int MENU_ITEM_ORDER_REPLACE = 9;
private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 10;
// Each Editor manages its own undo stack.
@@ -184,6 +188,7 @@
boolean mDiscardNextActionUp;
boolean mIgnoreActionUpEvent;
+ private boolean mIgnoreNextMouseActionUpOrDown;
long mShowCursor;
Blink mBlink;
@@ -209,6 +214,8 @@
boolean mPreserveDetachedSelection;
boolean mTemporaryDetach;
+ boolean mIsBeingLongClicked;
+
SuggestionsPopupWindow mSuggestionsPopupWindow;
SuggestionRangeSpan mSuggestionRangeSpan;
Runnable mShowSuggestionRunnable;
@@ -224,6 +231,7 @@
private PositionListener mPositionListener;
float mLastDownPositionX, mLastDownPositionY;
+ private float mContextMenuAnchorX, mContextMenuAnchorY;
Callback mCustomSelectionActionModeCallback;
Callback mCustomInsertionActionModeCallback;
@@ -239,6 +247,9 @@
// Only for mouse input.
private static final int TAP_STATE_TRIPLE_CLICK = 3;
+ // The button state as of the last time #onTouchEvent is called.
+ private int mLastButtonState;
+
private Runnable mInsertionActionModeRunnable;
// The span controller helps monitoring the changes to which the Editor needs to react:
@@ -1314,7 +1325,33 @@
}
}
+ private boolean shouldFilterOutTouchEvent(MotionEvent event) {
+ if (!event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+ return false;
+ }
+ final boolean primaryButtonStateChanged =
+ ((mLastButtonState ^ event.getButtonState()) & MotionEvent.BUTTON_PRIMARY) != 0;
+ final int action = event.getActionMasked();
+ if ((action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_UP)
+ && !primaryButtonStateChanged) {
+ return true;
+ }
+ if (action == MotionEvent.ACTION_MOVE
+ && !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) {
+ return true;
+ }
+ return false;
+ }
+
void onTouchEvent(MotionEvent event) {
+ final boolean filterOutEvent = shouldFilterOutTouchEvent(event);
+ mLastButtonState = event.getButtonState();
+ if (filterOutEvent) {
+ if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+ mDiscardNextActionUp = true;
+ }
+ return;
+ }
updateTapState(event);
updateFloatingToolbarVisibility(event);
@@ -2318,6 +2355,84 @@
text.setSpan(mSpanController, 0, textLength, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
+ void setContextMenuAnchor(float x, float y) {
+ mContextMenuAnchorX = x;
+ mContextMenuAnchorY = y;
+ }
+
+ void onCreateContextMenu(ContextMenu menu) {
+ if (mIsBeingLongClicked || Float.isNaN(mContextMenuAnchorX)
+ || Float.isNaN(mContextMenuAnchorY)) {
+ return;
+ }
+ final int offset = mTextView.getOffsetForPosition(mContextMenuAnchorX, mContextMenuAnchorY);
+ if (offset == -1) {
+ return;
+ }
+ final boolean isOnSelection = mTextView.hasSelection()
+ && offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
+ if (!isOnSelection) {
+ // Right clicked position is not on the selection. Remove the selection and move the
+ // cursor to the right clicked position.
+ stopTextActionMode();
+ Selection.setSelection((Spannable) mTextView.getText(), offset);
+ }
+
+ // TODO: Add suggestions in the context menu.
+
+ menu.add(Menu.NONE, TextView.ID_UNDO, MENU_ITEM_ORDER_UNDO,
+ com.android.internal.R.string.undo)
+ .setAlphabeticShortcut('z')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setEnabled(mTextView.canUndo());
+ menu.add(Menu.NONE, TextView.ID_REDO, MENU_ITEM_ORDER_REDO,
+ com.android.internal.R.string.redo)
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setEnabled(mTextView.canRedo());
+
+ menu.add(Menu.NONE, TextView.ID_CUT, MENU_ITEM_ORDER_CUT,
+ com.android.internal.R.string.cut)
+ .setAlphabeticShortcut('x')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setEnabled(mTextView.canCut());
+ menu.add(Menu.NONE, TextView.ID_COPY, MENU_ITEM_ORDER_COPY,
+ com.android.internal.R.string.copy)
+ .setAlphabeticShortcut('c')
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener)
+ .setEnabled(mTextView.canCopy());
+ menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE,
+ com.android.internal.R.string.paste)
+ .setAlphabeticShortcut('v')
+ .setEnabled(mTextView.canPaste())
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ menu.add(Menu.NONE, TextView.ID_PASTE, MENU_ITEM_ORDER_PASTE_AS_PLAIN_TEXT,
+ com.android.internal.R.string.paste_as_plain_text)
+ .setEnabled(mTextView.canPaste())
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ menu.add(Menu.NONE, TextView.ID_SHARE, MENU_ITEM_ORDER_SHARE,
+ com.android.internal.R.string.share)
+ .setEnabled(mTextView.canShare())
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+ menu.add(Menu.NONE, TextView.ID_SELECT_ALL, MENU_ITEM_ORDER_SELECT_ALL,
+ com.android.internal.R.string.selectAll)
+ .setAlphabeticShortcut('a')
+ .setEnabled(mTextView.canSelectAllText())
+ .setOnMenuItemClickListener(mOnContextMenuItemClickListener);
+
+ mPreserveDetachedSelection = true;
+ }
+
+ private final MenuItem.OnMenuItemClickListener mOnContextMenuItemClickListener =
+ new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) {
+ return true;
+ }
+ return mTextView.onTextContextMenuItem(item.getItemId());
+ }
+ };
+
/**
* Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
* pop-up should be displayed.
@@ -2710,6 +2825,9 @@
}
public void hide() {
+ if (!isShowing()) {
+ return;
+ }
mPopupWindow.dismiss();
getPositionListener().removeSubscriber(this);
}
@@ -2759,8 +2877,10 @@
@Override
public void dismiss() {
+ if (!isShowing()) {
+ return;
+ }
super.dismiss();
-
getPositionListener().removeSubscriber(SuggestionsPopupWindow.this);
// Safe cast since show() checks that mTextView.getText() is an Editable
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 607e955..ee73092 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1643,8 +1643,16 @@
boolean handled = false;
int action = event.getAction();
+ if (KeyEvent.isConfirmKey(keyCode)
+ && event.hasNoModifiers() && action == KeyEvent.ACTION_UP) {
+ handled = resurrectSelectionIfNeeded();
+ if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
+ keyPressed();
+ handled = true;
+ }
+ }
- if (action != KeyEvent.ACTION_UP) {
+ if (!handled && action != KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_LEFT:
if (event.hasNoModifiers()) {
@@ -1674,28 +1682,6 @@
}
break;
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- if (event.hasNoModifiers()) {
- handled = resurrectSelectionIfNeeded();
- if (!handled
- && event.getRepeatCount() == 0 && getChildCount() > 0) {
- keyPressed();
- handled = true;
- }
- }
- break;
-
- case KeyEvent.KEYCODE_SPACE:
- if (mPopup == null || !mPopup.isShowing()) {
- if (event.hasNoModifiers()) {
- handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
- } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
- handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
- }
- }
- break;
-
case KeyEvent.KEYCODE_PAGE_UP:
if (event.hasNoModifiers()) {
handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index ad939be..f6e6186 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -359,7 +359,6 @@
final int count = getVirtualChildCount();
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child != null && child.getVisibility() != GONE) {
if (hasDividerBeforeChildAt(i)) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -388,7 +387,7 @@
*/
private View getLastNonGoneChild() {
for (int i = getVirtualChildCount() - 1; i >= 0; i--) {
- View child = getVirtualChildAt(i);
+ final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
return child;
}
@@ -401,7 +400,6 @@
final boolean isLayoutRtl = isLayoutRtl();
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child != null && child.getVisibility() != GONE) {
if (hasDividerBeforeChildAt(i)) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -588,8 +586,9 @@
* for an example.</p>
*
* @param index the child's index
- * @return the child at the specified index
+ * @return the child at the specified index, may be {@code null}
*/
+ @Nullable
View getVirtualChildAt(int index) {
return getChildAt(index);
}
@@ -670,7 +669,7 @@
*/
private boolean allViewsAreGoneBefore(int childIndex) {
for (int i = childIndex - 1; i >= 0; i--) {
- View child = getVirtualChildAt(i);
+ final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
return false;
}
@@ -715,7 +714,6 @@
// See how tall everyone is. Also remember max width.
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -837,7 +835,6 @@
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -943,7 +940,6 @@
if (useLargestChild && heightMode != MeasureSpec.EXACTLY) {
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -986,7 +982,7 @@
MeasureSpec.EXACTLY);
for (int i = 0; i< count; ++i) {
final View child = getVirtualChildAt(i);
- if (child.getVisibility() != GONE) {
+ if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
if (lp.width == LayoutParams.MATCH_PARENT) {
@@ -1053,7 +1049,6 @@
// See how wide everyone is. Also remember max height.
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -1211,7 +1206,6 @@
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
-
if (child == null) {
mTotalLength += measureNullChild(i);
continue;
@@ -1357,7 +1351,6 @@
if (useLargestChild && widthMode != MeasureSpec.EXACTLY) {
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
-
if (child == null || child.getVisibility() == View.GONE) {
continue;
}
@@ -1402,7 +1395,7 @@
MeasureSpec.EXACTLY);
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
- if (child.getVisibility() != GONE) {
+ if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
if (lp.height == LayoutParams.MATCH_PARENT) {
@@ -1662,9 +1655,8 @@
}
for (int i = 0; i < count; i++) {
- int childIndex = start + dir * i;
+ final int childIndex = start + dir * i;
final View child = getVirtualChildAt(childIndex);
-
if (child == null) {
childLeft += measureNullChild(childIndex);
} else if (child.getVisibility() != GONE) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 53ca6d1..a11897d 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -2180,8 +2180,17 @@
boolean handled = false;
int action = event.getAction();
+ if (KeyEvent.isConfirmKey(keyCode)
+ && event.hasNoModifiers() && action != KeyEvent.ACTION_UP) {
+ handled = resurrectSelectionIfNeeded();
+ if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
+ keyPressed();
+ handled = true;
+ }
+ }
- if (action != KeyEvent.ACTION_UP) {
+
+ if (!handled && action != KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
if (event.hasNoModifiers()) {
@@ -2229,29 +2238,6 @@
}
break;
- case KeyEvent.KEYCODE_DPAD_CENTER:
- case KeyEvent.KEYCODE_ENTER:
- if (event.hasNoModifiers()) {
- handled = resurrectSelectionIfNeeded();
- if (!handled
- && event.getRepeatCount() == 0 && getChildCount() > 0) {
- keyPressed();
- handled = true;
- }
- }
- break;
-
- case KeyEvent.KEYCODE_SPACE:
- if (mPopup == null || !mPopup.isShowing()) {
- if (event.hasNoModifiers()) {
- handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_DOWN);
- } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
- handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
- }
- handled = true;
- }
- break;
-
case KeyEvent.KEYCODE_PAGE_UP:
if (event.hasNoModifiers()) {
handled = resurrectSelectionIfNeeded() || pageScroll(FOCUS_UP);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f4c343a..7e98193 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,6 +16,7 @@
package android.widget;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import com.android.internal.R;
@@ -1313,7 +1314,8 @@
p.width = mLastWidth = mWidth;
}
- p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+ p.privateFlags = PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH
+ | PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
// Used for debugging.
p.setTitle("PopupWindow:" + Integer.toHexString(hashCode()));
@@ -1465,10 +1467,14 @@
}
if (mClipToScreen) {
+ final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
+ final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
+ p.x += winOffsetX;
+ p.y += winOffsetY;
final int displayFrameWidth = displayFrame.right - displayFrame.left;
final int right = p.x + p.width;
- if (right > displayFrameWidth) {
- p.x -= right - displayFrameWidth;
+ if (right > displayFrame.right) {
+ p.x -= right - displayFrame.right;
}
if (p.x < displayFrame.left) {
@@ -1477,10 +1483,9 @@
}
if (mOverlapAnchor) {
- final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
final int bottom = p.y + p.height;
if (bottom > displayFrame.bottom) {
- p.y -= bottom - displayFrameHeight;
+ p.y -= bottom - displayFrame.bottom;
}
} else {
if (onTop) {
@@ -1492,6 +1497,8 @@
p.y = Math.max(p.y, displayFrame.top);
}
}
+ p.x -= winOffsetX;
+ p.y -= winOffsetY;
}
p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index f7f9c91..22931fc 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -98,7 +98,7 @@
* {@hide}
*/
void setColumnCollapsed(int columnIndex, boolean collapsed) {
- View child = getVirtualChildAt(columnIndex);
+ final View child = getVirtualChildAt(columnIndex);
if (child != null) {
child.setVisibility(collapsed ? GONE : VISIBLE);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 17c803f..d46c6f9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -111,6 +111,7 @@
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.ActionMode;
import android.view.Choreographer;
+import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -393,7 +394,17 @@
mOverride = false;
}
- public void resolveWithLayoutDirection(int layoutDirection) {
+ /**
+ * Updates the list of displayed drawables to account for the current
+ * layout direction.
+ *
+ * @param layoutDirection the current layout direction
+ * @return {@code true} if the displayed drawables changed
+ */
+ public boolean resolveWithLayoutDirection(int layoutDirection) {
+ final Drawable previousLeft = mShowing[Drawables.LEFT];
+ final Drawable previousRight = mShowing[Drawables.RIGHT];
+
// First reset "left" and "right" drawables to their initial values
mShowing[Drawables.LEFT] = mDrawableLeftInitial;
mShowing[Drawables.RIGHT] = mDrawableRightInitial;
@@ -441,16 +452,11 @@
break;
}
}
- applyErrorDrawableIfNeeded(layoutDirection);
- updateDrawablesLayoutDirection(layoutDirection);
- }
- private void updateDrawablesLayoutDirection(int layoutDirection) {
- for (Drawable dr : mShowing) {
- if (dr != null) {
- dr.setLayoutDirection(layoutDirection);
- }
- }
+ applyErrorDrawableIfNeeded(layoutDirection);
+
+ return mShowing[Drawables.LEFT] != previousLeft
+ || mShowing[Drawables.RIGHT] != previousRight;
}
public void setErrorDrawable(Drawable dr, TextView tv) {
@@ -5957,6 +5963,14 @@
@Override
public PointerIcon getPointerIcon(MotionEvent event, float x, float y) {
+ if (mText instanceof Spannable && mLinksClickable) {
+ final int offset = getOffsetForPosition(x, y);
+ final ClickableSpan[] clickables = ((Spannable) mText).getSpans(offset, offset,
+ ClickableSpan.class);
+ if (clickables.length > 0) {
+ return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_HAND);
+ }
+ }
if (isTextSelectable() || isTextEditable()) {
return PointerIcon.getSystemIcon(mContext, PointerIcon.STYLE_TEXT);
}
@@ -8489,6 +8503,29 @@
return super.onGenericMotionEvent(event);
}
+ @Override
+ protected void onCreateContextMenu(ContextMenu menu) {
+ if (mEditor != null) {
+ mEditor.onCreateContextMenu(menu);
+ }
+ }
+
+ @Override
+ public boolean showContextMenu() {
+ if (mEditor != null) {
+ mEditor.setContextMenuAnchor(Float.NaN, Float.NaN);
+ }
+ return super.showContextMenu();
+ }
+
+ @Override
+ public boolean showContextMenu(float x, float y) {
+ if (mEditor != null) {
+ mEditor.setContextMenuAnchor(x, y);
+ }
+ return super.showContextMenu(x, y);
+ }
+
/**
* @return True iff this TextView contains a text that can be edited, or if this is
* a selectable TextView.
@@ -9390,12 +9427,17 @@
public boolean performLongClick() {
boolean handled = false;
+ if (mEditor != null) {
+ mEditor.mIsBeingLongClicked = true;
+ }
+
if (super.performLongClick()) {
handled = true;
}
if (mEditor != null) {
handled |= mEditor.performLongClick(handled);
+ mEditor.mIsBeingLongClicked = false;
}
if (handled) {
@@ -9809,7 +9851,30 @@
// Resolve drawables
if (mDrawables != null) {
- mDrawables.resolveWithLayoutDirection(layoutDirection);
+ if (mDrawables.resolveWithLayoutDirection(layoutDirection)) {
+ prepareDrawableForDisplay(mDrawables.mShowing[Drawables.LEFT]);
+ prepareDrawableForDisplay(mDrawables.mShowing[Drawables.RIGHT]);
+ applyCompoundDrawableTint();
+ }
+ }
+ }
+
+ /**
+ * Prepares a drawable for display by propagating layout direction and
+ * drawable state.
+ *
+ * @param dr the drawable to prepare
+ */
+ private void prepareDrawableForDisplay(@Nullable Drawable dr) {
+ if (dr == null) {
+ return;
+ }
+
+ dr.setLayoutDirection(getLayoutDirection());
+
+ if (dr.isStateful()) {
+ dr.setState(getDrawableState());
+ dr.jumpToCurrentState();
}
}
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index acbf5eb..8e711b0 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -2070,7 +2070,7 @@
MenuItemImpl mCurrentExpandedItem;
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
// Clear the expanded action view when menus change.
if (mMenu != null && mCurrentExpandedItem != null) {
mMenu.collapseItemActionView(mCurrentExpandedItem);
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 61ee00c..27c3b72 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -359,6 +359,7 @@
if (mIconView != null) {
if (resId != 0) {
+ mIconView.setVisibility(View.VISIBLE);
mIconView.setImageResource(mIconId);
} else {
mIconView.setVisibility(View.GONE);
@@ -377,6 +378,7 @@
if (mIconView != null) {
if (icon != null) {
+ mIconView.setVisibility(View.VISIBLE);
mIconView.setImageDrawable(icon);
} else {
mIconView.setVisibility(View.GONE);
diff --git a/core/java/com/android/internal/app/EphemeralResolveInfo.java b/core/java/com/android/internal/app/EphemeralResolveInfo.java
deleted file mode 100644
index 0e7ef05..0000000
--- a/core/java/com/android/internal/app/EphemeralResolveInfo.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.IntentFilter;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Information that is returned when resolving ephemeral
- * applications.
- */
-public final class EphemeralResolveInfo implements Parcelable {
- public static final String SHA_ALGORITHM = "SHA-256";
- private byte[] mDigestBytes;
- private int mDigestPrefix;
- private final List<IntentFilter> mFilters = new ArrayList<IntentFilter>();
-
- public EphemeralResolveInfo(Uri uri, List<IntentFilter> filters) {
- generateDigest(uri);
- mFilters.addAll(filters);
- }
-
- private EphemeralResolveInfo(Parcel in) {
- readFromParcel(in);
- }
-
- public byte[] getDigestBytes() {
- return mDigestBytes;
- }
-
- public int getDigestPrefix() {
- return mDigestPrefix;
- }
-
- public List<IntentFilter> getFilters() {
- return mFilters;
- }
-
- private void generateDigest(Uri uri) {
- try {
- final MessageDigest digest = MessageDigest.getInstance(SHA_ALGORITHM);
- final byte[] hostBytes = uri.getHost().getBytes();
- final byte[] digestBytes = digest.digest(hostBytes);
- mDigestBytes = digestBytes;
- mDigestPrefix =
- digestBytes[0] << 24
- | digestBytes[1] << 16
- | digestBytes[2] << 8
- | digestBytes[3] << 0;
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("could not find digest algorithm");
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- if (mDigestBytes == null) {
- out.writeInt(0);
- } else {
- out.writeInt(mDigestBytes.length);
- out.writeByteArray(mDigestBytes);
- }
- out.writeInt(mDigestPrefix);
- out.writeList(mFilters);
- }
-
- private void readFromParcel(Parcel in) {
- int digestBytesSize = in.readInt();
- if (digestBytesSize > 0) {
- mDigestBytes = new byte[digestBytesSize];
- in.readByteArray(mDigestBytes);
- }
- mDigestPrefix = in.readInt();
- in.readList(mFilters, null /*loader*/);
- }
-
- public static final Parcelable.Creator<EphemeralResolveInfo> CREATOR
- = new Parcelable.Creator<EphemeralResolveInfo>() {
- public EphemeralResolveInfo createFromParcel(Parcel in) {
- return new EphemeralResolveInfo(in);
- }
-
- public EphemeralResolveInfo[] newArray(int size) {
- return new EphemeralResolveInfo[size];
- }
- };
-}
diff --git a/core/java/com/android/internal/app/EphemeralResolverService.java b/core/java/com/android/internal/app/EphemeralResolverService.java
index 65530f2..6ba04a9 100644
--- a/core/java/com/android/internal/app/EphemeralResolverService.java
+++ b/core/java/com/android/internal/app/EphemeralResolverService.java
@@ -16,9 +16,11 @@
package com.android.internal.app;
+import android.annotation.SystemApi;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.EphemeralResolveInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -33,6 +35,7 @@
* Base class for implementing the resolver service.
* @hide
*/
+@SystemApi
public abstract class EphemeralResolverService extends Service {
public static final String EXTRA_RESOLVE_INFO = "com.android.internal.app.RESOLVE_INFO";
public static final String EXTRA_SEQUENCE = "com.android.internal.app.SEQUENCE";
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 4efefa9..6a365e0 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.provider.Settings;
+import android.util.LocaleList;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -45,6 +46,7 @@
public class LocalePicker extends ListFragment {
private static final String TAG = "LocalePicker";
private static final boolean DEBUG = false;
+ private static final String[] pseudoLocales = { "en-XA", "ar-XB" };
public static interface LocaleSelectionListener {
// You can add any argument if you really need it...
@@ -57,7 +59,7 @@
static final Collator sCollator = Collator.getInstance();
String label;
- Locale locale;
+ final Locale locale;
public LocaleInfo(String label, Locale locale) {
this.label = label;
@@ -83,17 +85,30 @@
}
}
+ public static String[] getSystemAssetLocales() {
+ return Resources.getSystem().getAssets().getLocales();
+ }
+
+ public static String[] getSupportedLocales(Context context) {
+ return context.getResources().getStringArray(R.array.supported_locales);
+ }
+
+ public static String[] getPseudoLocales() {
+ return pseudoLocales;
+ }
+
public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
final Resources resources = context.getResources();
- final String[] locales = Resources.getSystem().getAssets().getLocales();
+ final String[] locales = getSystemAssetLocales();
List<String> localeList = new ArrayList<String>(locales.length);
Collections.addAll(localeList, locales);
// Don't show the pseudolocales unless we're in developer mode. http://b/17190407.
if (!isInDeveloperMode) {
- localeList.remove("ar-XB");
- localeList.remove("en-XA");
+ for (String locale : pseudoLocales) {
+ localeList.remove(locale);
+ }
}
Collections.sort(localeList);
@@ -240,13 +255,24 @@
/**
* Requests the system to update the system locale. Note that the system looks halted
* for a while during the Locale migration, so the caller need to take care of it.
+ *
+ * @see #updateLocales(LocaleList)
*/
public static void updateLocale(Locale locale) {
- try {
- IActivityManager am = ActivityManagerNative.getDefault();
- Configuration config = am.getConfiguration();
+ updateLocales(new LocaleList(locale));
+ }
- config.setLocale(locale);
+ /**
+ * Requests the system to update the list of system locales.
+ * Note that the system looks halted for a while during the Locale migration,
+ * so the caller need to take care of it.
+ */
+ public static void updateLocales(LocaleList locales) {
+ try {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ final Configuration config = am.getConfiguration();
+
+ config.setLocales(locales);
config.userSetLocale = true;
am.updateConfiguration(config);
@@ -256,4 +282,19 @@
// Intentionally left blank
}
}
+
+ /**
+ * Get the locale list.
+ *
+ * @return The locale list.
+ */
+ public static LocaleList getLocales() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .getConfiguration().getLocales();
+ } catch (RemoteException e) {
+ // If something went wrong
+ return LocaleList.getDefault();
+ }
+ }
}
diff --git a/core/java/com/android/internal/app/LocalePickerWithRegion.java b/core/java/com/android/internal/app/LocalePickerWithRegion.java
new file mode 100644
index 0000000..3b8f865
--- /dev/null
+++ b/core/java/com/android/internal/app/LocalePickerWithRegion.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 com.android.internal.R;
+
+import android.app.ListFragment;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+class LocaleAdapter extends ArrayAdapter<LocalePicker.LocaleInfo> {
+ final private Map<String, LocalePicker.LocaleInfo> mLevelOne = new ArrayMap<>();
+ final private Map<String, HashSet<LocalePicker.LocaleInfo>> mLevelTwo = new ArrayMap<>();
+ final private LayoutInflater mInflater;
+
+ final static class LocaleAwareComparator implements Comparator<LocalePicker.LocaleInfo> {
+ private final Collator mCollator;
+
+ public LocaleAwareComparator(Locale sortLocale) {
+ mCollator = Collator.getInstance(sortLocale);
+ }
+
+ @Override
+ public int compare(LocalePicker.LocaleInfo lhs, LocalePicker.LocaleInfo rhs) {
+ return mCollator.compare(lhs.getLabel(), rhs.getLabel());
+ }
+ }
+
+ static List<Locale> getCuratedLocaleList(Context context) {
+ final Resources resources = context.getResources();
+ final String[] supportedLocaleCodes = resources.getStringArray(R.array.supported_locales);
+
+ final ArrayList<Locale> result = new ArrayList<>(supportedLocaleCodes.length);
+ for (String localeId : supportedLocaleCodes) {
+ Locale locale = Locale.forLanguageTag(localeId);
+ if (!locale.getCountry().isEmpty()) {
+ result.add(Locale.forLanguageTag(localeId));
+ }
+ }
+ return result;
+ }
+
+ public LocaleAdapter(Context context) {
+ this(context, getCuratedLocaleList(context));
+ }
+
+ static Locale getBaseLocale(Locale locale) {
+ return new Locale.Builder()
+ .setLocale(locale)
+ .setRegion("")
+ .build();
+ }
+
+ // There is no good API available for this, not even in ICU.
+ // We can revisit this if we get some ICU support later
+ //
+ // There are currently several tickets requesting this feature:
+ // * ICU needs to provide an easy way to titlecase only one first letter
+ // http://bugs.icu-project.org/trac/ticket/11729
+ // * Add "initial case"
+ // http://bugs.icu-project.org/trac/ticket/8394
+ // * Add code for initialCase, toTitlecase don't modify after Lt,
+ // avoid 49Ers, low-level language-specific casing
+ // http://bugs.icu-project.org/trac/ticket/10410
+ // * BreakIterator.getFirstInstance: Often you need to titlecase just the first
+ // word, and leave the rest of the string alone. (closed as duplicate)
+ // http://bugs.icu-project.org/trac/ticket/8946
+ //
+ // A (clunky) option with the current ICU API is:
+ // BreakIterator breakIterator = BreakIterator.getSentenceInstance(locale);
+ // String result = UCharacter.toTitleCase(locale,
+ // source, breakIterator, UCharacter.TITLECASE_NO_LOWERCASE);
+ // That also means creating BreakIteratos for each locale. Expensive...
+ private static String toTitleCase(String s, Locale locale) {
+ if (s.length() == 0) {
+ return s;
+ }
+ final int firstCodePointLen = s.offsetByCodePoints(0, 1);
+ return s.substring(0, firstCodePointLen).toUpperCase(locale)
+ + s.substring(firstCodePointLen);
+ }
+
+ public LocaleAdapter(Context context, List<Locale> locales) {
+ super(context, R.layout.locale_picker_item, R.id.locale);
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ for (Locale locale : locales) {
+ Locale baseLocale = getBaseLocale(locale);
+ String language = baseLocale.toLanguageTag();
+ if (!mLevelOne.containsKey(language)) {
+ String label = toTitleCase(baseLocale.getDisplayName(baseLocale), baseLocale);
+ mLevelOne.put(language, new LocalePicker.LocaleInfo(label, baseLocale));
+ }
+
+ final HashSet<LocalePicker.LocaleInfo> subLocales;
+ if (mLevelTwo.containsKey(language)) {
+ subLocales = mLevelTwo.get(language);
+ } else {
+ subLocales = new HashSet<>();
+ mLevelTwo.put(language, subLocales);
+ }
+ String label = locale.getDisplayCountry(locale);
+ subLocales.add(new LocalePicker.LocaleInfo(label, locale));
+ }
+
+ setAdapterLevel(null);
+ }
+
+ public void setAdapterLevel(String parentLocale) {
+ this.clear();
+
+ if (parentLocale == null) {
+ this.addAll(mLevelOne.values());
+ } else {
+ this.addAll(mLevelTwo.get(parentLocale));
+ }
+
+ Locale sortLocale = (parentLocale == null)
+ ? Locale.getDefault()
+ : Locale.forLanguageTag(parentLocale);
+ LocaleAwareComparator comparator = new LocaleAwareComparator(sortLocale);
+ this.sort(comparator);
+
+ this.notifyDataSetChanged();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view;
+ TextView text;
+ if (convertView == null) {
+ view = mInflater.inflate(R.layout.locale_picker_item, parent, false);
+ text = (TextView) view.findViewById(R.id.locale);
+ view.setTag(text);
+ } else {
+ view = convertView;
+ text = (TextView) view.getTag();
+ }
+ LocalePicker.LocaleInfo item = getItem(position);
+ text.setText(item.getLabel());
+ text.setTextLocale(item.getLocale());
+ return view;
+ }
+}
+
+public class LocalePickerWithRegion extends ListFragment {
+ private static final int LIST_MODE_LANGUAGE = 0;
+ private static final int LIST_MODE_COUNTRY = 1;
+
+ private LocaleAdapter mAdapter;
+ private int mDisplayMode = LIST_MODE_LANGUAGE;
+
+ public static interface LocaleSelectionListener {
+ // You can add any argument if you really need it...
+ public void onLocaleSelected(Locale locale);
+ }
+
+ private LocaleSelectionListener mListener = null;
+
+ @Override
+ public void onActivityCreated(final Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ mAdapter = new LocaleAdapter(getContext());
+ mAdapter.setAdapterLevel(null);
+ setListAdapter(mAdapter);
+ }
+
+ public void setLocaleSelectionListener(LocaleSelectionListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ getListView().requestFocus();
+ }
+
+ /**
+ * Each listener needs to call {@link LocalePicker.updateLocale(Locale)} to actually
+ * change the locale.
+ * <p/>
+ * We don't call {@link LocalePicker.updateLocale(Locale)} automatically, as it halts
+ * the system for a moment and some callers won't want it.
+ */
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ final Locale locale = ((LocalePicker.LocaleInfo) getListAdapter().getItem(position)).locale;
+ // TODO: handle the back buttons to return to the language list
+ if (mDisplayMode == LIST_MODE_LANGUAGE) {
+ mDisplayMode = LIST_MODE_COUNTRY;
+ mAdapter.setAdapterLevel(locale.toLanguageTag());
+ return;
+ }
+ if (mListener != null) {
+ mListener.onLocaleSelected(locale);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba0912a..aa38de7 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -718,9 +718,9 @@
if (ri.handleAllWebDataURI) {
// Set default Browser if needed
- final String packageName = pm.getDefaultBrowserPackageName(userId);
+ final String packageName = pm.getDefaultBrowserPackageNameAsUser(userId);
if (TextUtils.isEmpty(packageName)) {
- pm.setDefaultBrowserPackageName(ri.activityInfo.packageName, userId);
+ pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
}
} else {
// Update Domain Verification status
@@ -737,7 +737,7 @@
categories.contains(Intent.CATEGORY_BROWSABLE);
if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
- pm.updateIntentVerificationStatus(packageName,
+ pm.updateIntentVerificationStatusAsUser(packageName,
PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
userId);
}
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 9d12803..575ef02 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -29,10 +29,14 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.Window;
import android.view.WindowCallbackWrapper;
import android.widget.SpinnerAdapter;
import android.widget.Toolbar;
+
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.widget.DecorToolbar;
@@ -479,6 +483,12 @@
return true;
}
+ @Override
+ public void onDestroy() {
+ // Remove any invalidation callbacks
+ mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+ }
+
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
mMenuVisibilityListeners.add(listener);
}
@@ -499,6 +509,12 @@
}
}
+ /** @hide */
+ @Override
+ public boolean requestFocus() {
+ return requestFocus(mDecorToolbar.getViewGroup());
+ }
+
private class ToolbarCallbackWrapper extends WindowCallbackWrapper {
public ToolbarCallbackWrapper(Window.Callback wrapped) {
super(wrapped);
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index 05cfd81..c6bf1b4 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -18,6 +18,8 @@
import android.animation.ValueAnimator;
import android.content.res.TypedArray;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.Toolbar;
@@ -950,6 +952,12 @@
return false;
}
+ /** @hide */
+ @Override
+ public boolean requestFocus() {
+ return requestFocus(mDecorToolbar.getViewGroup());
+ }
+
/**
* @hide
*/
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index e276bc6..4b821ab 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -35,6 +35,9 @@
public static final int ACTION_ZEN_ALLOW_LIGHTS = 262;
public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
+ public static final int QS_COLOR_MATRIX = 265;
+ public static final int QS_CUSTOM = 266;
+ public static final int ACTION_ZEN_ALLOW_SCREEN_ON = 267;
/**
* Logged when the user docks a window from recents by longpressing a task and dragging it to
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 8e318a2..4a1f7f4 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -534,7 +534,7 @@
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index e405564..cc2f714 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -17,6 +17,7 @@
package com.android.internal.policy;
import com.android.internal.R;
+import com.android.internal.policy.PhoneWindow.PhoneWindowMenuCallback;
import com.android.internal.view.FloatingActionMode;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.StandaloneActionMode;
@@ -67,8 +68,10 @@
import android.widget.FrameLayout;
import android.widget.PopupWindow;
+import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.getMode;
@@ -191,7 +194,12 @@
private Drawable mCaptionBackgroundDrawable;
private Drawable mUserCaptionBackgroundDrawable;
- DecorView(Context context, int featureId, PhoneWindow window) {
+ private float mAvailableWidth;
+
+ String mLogTag = TAG;
+
+ DecorView(Context context, int featureId, PhoneWindow window,
+ WindowManager.LayoutParams params) {
super(context);
mFeatureId = featureId;
@@ -207,7 +215,11 @@
mSemiTransparentStatusBarColor = context.getResources().getColor(
R.color.system_bar_background_semi_transparent, null /* theme */);
+ updateAvailableWidth();
+
setWindow(window);
+
+ updateLogTag(params);
}
void setBackgroundFallback(int resId) {
@@ -405,7 +417,7 @@
if (mFeatureId >= 0) {
if (action == MotionEvent.ACTION_DOWN) {
- Log.i(TAG, "Watchiing!");
+ Log.i(mLogTag, "Watchiing!");
mWatchingForMenu = true;
mDownY = (int) event.getY();
return false;
@@ -418,7 +430,7 @@
int y = (int)event.getY();
if (action == MotionEvent.ACTION_MOVE) {
if (y > (mDownY+30)) {
- Log.i(TAG, "Closing!");
+ Log.i(mLogTag, "Closing!");
mWindow.closePanel(mFeatureId);
mWatchingForMenu = false;
return true;
@@ -430,13 +442,13 @@
return false;
}
- //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY()
+ //Log.i(mLogTag, "Intercept: action=" + action + " y=" + event.getY()
// + " (in " + getHeight() + ")");
if (action == MotionEvent.ACTION_DOWN) {
int y = (int)event.getY();
if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
- Log.i(TAG, "Watching!");
+ Log.i(mLogTag, "Watching!");
mWatchingForMenu = true;
}
return false;
@@ -449,7 +461,7 @@
int y = (int)event.getY();
if (action == MotionEvent.ACTION_MOVE) {
if (y < (getHeight()-30)) {
- Log.i(TAG, "Opening!");
+ Log.i(mLogTag, "Opening!");
mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent(
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
mWatchingForMenu = false;
@@ -540,15 +552,15 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
- final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+ final boolean isPortrait =
+ getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT;
final int widthMode = getMode(widthMeasureSpec);
final int heightMode = getMode(heightMeasureSpec);
boolean fixedWidth = false;
if (widthMode == AT_MOST) {
- final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor
- : mWindow.mFixedWidthMajor;
+ final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor : mWindow.mFixedWidthMajor;
if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
final int w;
if (tvw.type == TypedValue.TYPE_DIMENSION) {
@@ -620,7 +632,7 @@
if (tv.type == TypedValue.TYPE_DIMENSION) {
min = (int)tv.getDimension(metrics);
} else if (tv.type == TypedValue.TYPE_FRACTION) {
- min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
+ min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth);
} else {
min = 0;
}
@@ -684,9 +696,10 @@
}
// Reuse the context menu builder.
+ final PhoneWindowMenuCallback callback = mWindow.mContextMenuCallback;
if (mWindow.mContextMenu == null) {
mWindow.mContextMenu = new ContextMenuBuilder(getContext());
- mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
+ mWindow.mContextMenu.setCallback(callback);
} else {
mWindow.mContextMenu.clearAll();
}
@@ -699,7 +712,11 @@
}
if (helper != null) {
- helper.setPresenterCallback(mWindow.mContextMenuCallback);
+ // If it's a dialog, the callback needs to handle showing
+ // sub-menus. Either way, the callback is required for propagating
+ // selection to Context.onContextMenuItemSelected().
+ callback.setShowDialogForSubmenu(!isPopup);
+ helper.setPresenterCallback(callback);
}
mWindow.mContextMenuHelper = helper;
@@ -1188,7 +1205,7 @@
invalidate();
int opacity = PixelFormat.OPAQUE;
- if (ActivityManager.StackId.hasWindowShadow(mStackId)) {
+ if (StackId.hasWindowShadow(mStackId)) {
// If the window has a shadow, it must be translucent.
opacity = PixelFormat.TRANSLUCENT;
} else{
@@ -1209,7 +1226,7 @@
int fop = fg.getOpacity();
int bop = bg.getOpacity();
if (false)
- Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop);
+ Log.v(mLogTag, "Background opacity: " + bop + ", Frame opacity: " + fop);
if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) {
opacity = PixelFormat.OPAQUE;
} else if (fop == PixelFormat.UNKNOWN) {
@@ -1224,16 +1241,16 @@
// frame with padding... there is no way to tell if the
// frame and background together will draw all pixels.
if (false)
- Log.v(TAG, "Padding: " + mFramePadding);
+ Log.v(mLogTag, "Padding: " + mFramePadding);
opacity = PixelFormat.TRANSLUCENT;
}
}
if (false)
- Log.v(TAG, "Background: " + bg + ", Frame: " + fg);
+ Log.v(mLogTag, "Background: " + bg + ", Frame: " + fg);
}
if (false)
- Log.v(TAG, "Selected default opacity: " + opacity);
+ Log.v(mLogTag, "Selected default opacity: " + opacity);
mDefaultOpacity = opacity;
if (mFeatureId < 0) {
@@ -1571,15 +1588,28 @@
void onConfigurationChanged() {
int workspaceId = getStackId();
- if (mDecorCaptionView != null) {
- if (mStackId != workspaceId) {
- mStackId = workspaceId;
+ if (mStackId != workspaceId) {
+ mStackId = workspaceId;
+ if (mDecorCaptionView == null && StackId.hasWindowDecor(mStackId)) {
+ // Configuration now requires a caption.
+ final LayoutInflater inflater = mWindow.getLayoutInflater();
+ mDecorCaptionView = createDecorCaptionView(inflater);
+ if (mDecorCaptionView != null) {
+ if (mDecorCaptionView.getParent() == null) {
+ addView(mDecorCaptionView, 0,
+ new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
+ removeView(mContentRoot);
+ mDecorCaptionView.addView(mContentRoot,
+ new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));
+ }
+ } else if (mDecorCaptionView != null) {
// We might have to change the kind of surface before we do anything else.
- mDecorCaptionView.onConfigurationChanged(
- ActivityManager.StackId.hasWindowDecor(mStackId));
- enableCaption(ActivityManager.StackId.hasWindowDecor(workspaceId));
+ mDecorCaptionView.onConfigurationChanged(StackId.hasWindowDecor(mStackId));
+ enableCaption(StackId.hasWindowDecor(workspaceId));
}
}
+ updateAvailableWidth();
initializeElevation();
}
@@ -1630,8 +1660,7 @@
final boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
attrs.type == TYPE_APPLICATION;
// Only a non floating application window on one of the allowed workspaces can get a caption
- if (!mWindow.isFloating() && isApplication
- && ActivityManager.StackId.hasWindowDecor(mStackId)) {
+ if (!mWindow.isFloating() && isApplication && StackId.hasWindowDecor(mStackId)) {
// Dependent on the brightness of the used title we either use the
// dark or the light button frame.
if (decorCaptionView == null) {
@@ -1725,7 +1754,7 @@
// We shouldn't really get here as the background fallback should be always available since
// it is defaulted by the system.
- Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + mWindow);
+ Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow);
return null;
}
@@ -1742,7 +1771,7 @@
try {
workspaceId = callback.getWindowStackId();
} catch (RemoteException ex) {
- Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
+ Log.e(mLogTag, "Failed to get the workspace ID of a PhoneWindow.");
}
}
if (workspaceId == INVALID_STACK_ID) {
@@ -1854,7 +1883,7 @@
final boolean wasAdjustedForStack = mElevationAdjustedForStack;
// Do not use a shadow when we are in resizing mode (mBackdropFrameRenderer not null)
// since the shadow is bound to the content size and not the target size.
- if (ActivityManager.StackId.hasWindowShadow(mStackId) && !isResizing()) {
+ if (StackId.hasWindowShadow(mStackId) && !isResizing()) {
elevation = hasWindowFocus() ?
DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
// TODO(skuhne): Remove this if clause once b/22668382 got fixed.
@@ -1908,6 +1937,19 @@
}
}
+ void updateLogTag(WindowManager.LayoutParams params) {
+ final String[] split = params.getTitle().toString().split("\\.");
+ if (split.length > 0) {
+ mLogTag = TAG + "[" + split[split.length - 1] + "]";
+ }
+ }
+
+ private void updateAvailableWidth() {
+ Resources res = getResources();
+ mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ res.getConfiguration().screenWidthDp, res.getDisplayMetrics());
+ }
+
private static class ColorViewState {
View view = null;
int targetVisibility = View.INVISIBLE;
@@ -1969,12 +2011,12 @@
isPrimary = mode == mPrimaryActionMode;
isFloating = mode == mFloatingActionMode;
if (!isPrimary && mode.getType() == ActionMode.TYPE_PRIMARY) {
- Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
+ Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; "
+ mode + " was not the current primary action mode! Expected "
+ mPrimaryActionMode);
}
if (!isFloating && mode.getType() == ActionMode.TYPE_FLOATING) {
- Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
+ Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_FLOATING; "
+ mode + " was not the current floating action mode! Expected "
+ mFloatingActionMode);
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 86bd782..f159a4d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -113,6 +113,8 @@
private final static String TAG = "PhoneWindow";
+ private static final boolean DEBUG = false;
+
private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300;
private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES |
@@ -127,7 +129,7 @@
* Simple callback used by the context menu and its submenus. The options
* menu submenus do not use this (their behavior is more complex).
*/
- final DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU);
+ final PhoneWindowMenuCallback mContextMenuCallback = new PhoneWindowMenuCallback(this);
final TypedValue mMinWidthMajor = new TypedValue();
final TypedValue mMinWidthMinor = new TypedValue();
@@ -146,6 +148,9 @@
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
+ // Whether the client has explicitly set the content view. If false and mContentParent is not
+ // null, then the content parent was set due to window preservation.
+ private boolean mContentParentExplicitlySet = false;
Callback2 mTakeSurfaceCallback;
@@ -274,6 +279,8 @@
private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
+ private boolean mUseDecorContext = false;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -286,8 +293,14 @@
mLayoutInflater = LayoutInflater.from(context);
}
+ /**
+ * Constructor for main window of an activity.
+ */
public PhoneWindow(Context context, Window preservedWindow) {
this(context);
+ // Only main activity windows use decor context, all the other windows depend on whatever
+ // context that was given to them.
+ mUseDecorContext = true;
if (preservedWindow != null) {
mDecor = (DecorView) preservedWindow.getDecorView();
mElevation = preservedWindow.getElevation();
@@ -307,7 +320,7 @@
@Override
public boolean requestFeature(int featureId) {
- if (mContentParent != null) {
+ if (mContentParentExplicitlySet) {
throw new AndroidRuntimeException("requestFeature() must be called before adding content");
}
final int features = getFeatures();
@@ -391,6 +404,7 @@
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
+ mContentParentExplicitlySet = true;
}
@Override
@@ -421,6 +435,7 @@
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
+ mContentParentExplicitlySet = true;
}
@Override
@@ -662,6 +677,13 @@
}
}
+ @Override
+ public void onMultiWindowModeChanged() {
+ if (mDecor != null) {
+ mDecor.onConfigurationChanged();
+ }
+ }
+
private static void clearMenuViews(PanelFeatureState st) {
// This can be called on config changes, so we should make sure
// the views will be reconstructed based on the new orientation, etc.
@@ -2252,17 +2274,21 @@
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
- Context applicationContext = getContext().getApplicationContext();
Context context;
- if (applicationContext == null) {
- context = getContext();
- } else {
- context = new DecorContext(applicationContext);
- if (mTheme != -1) {
- context.setTheme(mTheme);
+ if (mUseDecorContext) {
+ Context applicationContext = getContext().getApplicationContext();
+ if (applicationContext == null) {
+ context = getContext();
+ } else {
+ context = new DecorContext(applicationContext);
+ if (mTheme != -1) {
+ context.setTheme(mTheme);
+ }
}
+ } else {
+ context = getContext();
}
- return new DecorView(context, featureId, this);
+ return new DecorView(context, featureId, this, getAttributes());
}
protected ViewGroup generateLayout(DecorView decor) {
@@ -2341,6 +2367,8 @@
a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+ if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString()
+ + ", major: " + mMinWidthMajor.coerceToString());
if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) {
if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
a.getValue(R.styleable.Window_windowFixedWidthMajor,
@@ -3592,27 +3620,34 @@
* <li> Calls back to the callback's onMenuItemSelected when an item is
* selected.
*/
- private final class DialogMenuCallback implements MenuBuilder.Callback, MenuPresenter.Callback {
- private int mFeatureId;
+ public static final class PhoneWindowMenuCallback
+ implements MenuBuilder.Callback, MenuPresenter.Callback {
+ private static final int FEATURE_ID = FEATURE_CONTEXT_MENU;
+
+ private final PhoneWindow mWindow;
+
private MenuDialogHelper mSubMenuHelper;
- public DialogMenuCallback(int featureId) {
- mFeatureId = featureId;
+ private boolean mShowDialogForSubmenu;
+
+ public PhoneWindowMenuCallback(PhoneWindow window) {
+ mWindow = window;
}
+ @Override
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
if (menu.getRootMenu() != menu) {
onCloseSubMenu(menu);
}
if (allMenusAreClosing) {
- Callback callback = getCallback();
- if (callback != null && !isDestroyed()) {
- callback.onPanelClosed(mFeatureId, menu);
+ final Callback callback = mWindow.getCallback();
+ if (callback != null && !mWindow.isDestroyed()) {
+ callback.onPanelClosed(FEATURE_ID, menu);
}
- if (menu == mContextMenu) {
- dismissContextMenu();
+ if (menu == mWindow.mContextMenu) {
+ mWindow.dismissContextMenu();
}
// Dismiss the submenu, if it is showing
@@ -3623,33 +3658,45 @@
}
}
- public void onCloseSubMenu(MenuBuilder menu) {
- Callback callback = getCallback();
- if (callback != null && !isDestroyed()) {
- callback.onPanelClosed(mFeatureId, menu.getRootMenu());
+ private void onCloseSubMenu(MenuBuilder menu) {
+ final Callback callback = mWindow.getCallback();
+ if (callback != null && !mWindow.isDestroyed()) {
+ callback.onPanelClosed(FEATURE_ID, menu.getRootMenu());
}
}
+ @Override
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
- Callback callback = getCallback();
- return (callback != null && !isDestroyed())
- && callback.onMenuItemSelected(mFeatureId, item);
+ final Callback callback = mWindow.getCallback();
+ return callback != null && !mWindow.isDestroyed()
+ && callback.onMenuItemSelected(FEATURE_ID, item);
}
+ @Override
public void onMenuModeChange(MenuBuilder menu) {
}
+ @Override
public boolean onOpenSubMenu(MenuBuilder subMenu) {
- if (subMenu == null) return false;
+ if (subMenu == null) {
+ return false;
+ }
// Set a simple callback for the submenu
subMenu.setCallback(this);
- // The window manager will give us a valid window token
- mSubMenuHelper = new MenuDialogHelper(subMenu);
- mSubMenuHelper.show(null);
+ if (mShowDialogForSubmenu) {
+ // The window manager will give us a valid window token
+ mSubMenuHelper = new MenuDialogHelper(subMenu);
+ mSubMenuHelper.show(null);
+ return true;
+ }
- return true;
+ return false;
+ }
+
+ public void setShowDialogForSubmenu(boolean enabled) {
+ mShowDialogForSubmenu = enabled;
}
}
@@ -3738,4 +3785,12 @@
int getDecorCaptionShade() {
return mDecorCaptionShade;
}
+
+ @Override
+ public void setAttributes(WindowManager.LayoutParams params) {
+ super.setAttributes(params);
+ if (mDecor != null) {
+ mDecor.updateLogTag(params);
+ }
+ }
}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 849d314..4dd71e7 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -46,7 +46,7 @@
void cancelPreloadRecentApps();
void showScreenPinningRequest();
- void showKeyboardShortcutsMenu();
+ void toggleKeyboardShortcutsMenu();
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0a4ad06..0125d37 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -68,7 +68,7 @@
void preloadRecentApps();
void cancelPreloadRecentApps();
- void showKeyboardShortcutsMenu();
+ void toggleKeyboardShortcutsMenu();
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index e8970bc..16bf9dd 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -125,28 +125,28 @@
/**
* Checks if given array is null or has zero elements.
*/
- public static <T> boolean isEmpty(T[] array) {
+ public static <T> boolean isEmpty(@Nullable T[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
- public static boolean isEmpty(int[] array) {
+ public static boolean isEmpty(@Nullable int[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
- public static boolean isEmpty(long[] array) {
+ public static boolean isEmpty(@Nullable long[] array) {
return array == null || array.length == 0;
}
/**
* Checks if given array is null or has zero elements.
*/
- public static boolean isEmpty(byte[] array) {
+ public static boolean isEmpty(@Nullable byte[] array) {
return array == null || array.length == 0;
}
@@ -156,7 +156,7 @@
* @param value the value to check for
* @return true if the value is present in the array
*/
- public static <T> boolean contains(T[] array, T value) {
+ public static <T> boolean contains(@Nullable T[] array, T value) {
return indexOf(array, value) != -1;
}
@@ -164,7 +164,7 @@
* Return first index of {@code value} in {@code array}, or {@code -1} if
* not found.
*/
- public static <T> int indexOf(T[] array, T value) {
+ public static <T> int indexOf(@Nullable T[] array, T value) {
if (array == null) return -1;
for (int i = 0; i < array.length; i++) {
if (Objects.equals(array[i], value)) return i;
@@ -175,7 +175,7 @@
/**
* Test if all {@code check} items are contained in {@code array}.
*/
- public static <T> boolean containsAll(T[] array, T[] check) {
+ public static <T> boolean containsAll(@Nullable T[] array, T[] check) {
if (check == null) return true;
for (T checkItem : check) {
if (!contains(array, checkItem)) {
@@ -185,7 +185,7 @@
return true;
}
- public static boolean contains(int[] array, int value) {
+ public static boolean contains(@Nullable int[] array, int value) {
if (array == null) return false;
for (int element : array) {
if (element == value) {
@@ -195,7 +195,7 @@
return false;
}
- public static boolean contains(long[] array, long value) {
+ public static boolean contains(@Nullable long[] array, long value) {
if (array == null) return false;
for (long element : array) {
if (element == value) {
@@ -205,10 +205,12 @@
return false;
}
- public static long total(long[] array) {
+ public static long total(@Nullable long[] array) {
long total = 0;
- for (long value : array) {
- total += value;
+ if (array != null) {
+ for (long value : array) {
+ total += value;
+ }
}
return total;
}
@@ -366,11 +368,11 @@
return cur;
}
- public static long[] cloneOrNull(long[] array) {
+ public static @Nullable long[] cloneOrNull(@Nullable long[] array) {
return (array != null) ? array.clone() : null;
}
- public static <T> ArraySet<T> add(ArraySet<T> cur, T val) {
+ public static @NonNull <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {
if (cur == null) {
cur = new ArraySet<>();
}
@@ -378,7 +380,7 @@
return cur;
}
- public static <T> ArraySet<T> remove(ArraySet<T> cur, T val) {
+ public static @Nullable <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {
if (cur == null) {
return null;
}
@@ -390,11 +392,11 @@
}
}
- public static <T> boolean contains(ArraySet<T> cur, T val) {
+ public static <T> boolean contains(@Nullable ArraySet<T> cur, T val) {
return (cur != null) ? cur.contains(val) : false;
}
- public static <T> ArrayList<T> add(ArrayList<T> cur, T val) {
+ public static @NonNull <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
cur = new ArrayList<>();
}
@@ -402,7 +404,7 @@
return cur;
}
- public static <T> ArrayList<T> remove(ArrayList<T> cur, T val) {
+ public static @Nullable <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {
if (cur == null) {
return null;
}
@@ -414,7 +416,7 @@
}
}
- public static <T> boolean contains(ArrayList<T> cur, T val) {
+ public static <T> boolean contains(@Nullable ArrayList<T> cur, T val) {
return (cur != null) ? cur.contains(val) : false;
}
diff --git a/core/java/com/android/internal/util/LineBreakBufferedWriter.java b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
new file mode 100644
index 0000000..f831e7a
--- /dev/null
+++ b/core/java/com/android/internal/util/LineBreakBufferedWriter.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * A writer that breaks up its output into chunks before writing to its out writer,
+ * and which is linebreak aware, i.e., chunks will created along line breaks, if
+ * possible.
+ *
+ * Note: this class is not thread-safe.
+ */
+public class LineBreakBufferedWriter extends PrintWriter {
+
+ /**
+ * A buffer to collect data until the buffer size is reached.
+ *
+ * Note: we manage a char[] ourselves to avoid an allocation when printing to the
+ * out writer. Otherwise a StringBuilder would have been simpler to use.
+ */
+ private char[] buffer;
+
+ /**
+ * The index of the first free element in the buffer.
+ */
+ private int bufferIndex;
+
+ /**
+ * The chunk size (=maximum buffer size) to use for this writer.
+ */
+ private final int bufferSize;
+
+
+ /**
+ * Index of the last newline character discovered in the buffer. The writer will try
+ * to split there.
+ */
+ private int lastNewline = -1;
+
+ /**
+ * The line separator for println().
+ */
+ private final String lineSeparator;
+
+ /**
+ * Create a new linebreak-aware buffered writer with the given output and buffer
+ * size. The initial capacity will be a default value.
+ * @param out The writer to write to.
+ * @param bufferSize The maximum buffer size.
+ */
+ public LineBreakBufferedWriter(Writer out, int bufferSize) {
+ this(out, bufferSize, 16); // 16 is the default size of a StringBuilder buffer.
+ }
+
+ /**
+ * Create a new linebreak-aware buffered writer with the given output, buffer
+ * size and initial capacity.
+ * @param out The writer to write to.
+ * @param bufferSize The maximum buffer size.
+ * @param initialCapacity The initial capacity of the internal buffer.
+ */
+ public LineBreakBufferedWriter(Writer out, int bufferSize, int initialCapacity) {
+ super(out);
+ this.buffer = new char[Math.min(initialCapacity, bufferSize)];
+ this.bufferIndex = 0;
+ this.bufferSize = bufferSize;
+ this.lineSeparator = System.getProperty("line.separator");
+ }
+
+ /**
+ * Flush the current buffer. This will ignore line breaks.
+ */
+ @Override
+ public void flush() {
+ writeBuffer(bufferIndex);
+ bufferIndex = 0;
+ super.flush();
+ }
+
+ @Override
+ public void write(int c) {
+ if (bufferIndex < bufferSize) {
+ buffer[bufferIndex] = (char)c;
+ bufferIndex++;
+ if ((char)c == '\n') {
+ lastNewline = bufferIndex;
+ }
+ } else {
+ // This should be an uncommon case, we mostly expect char[] and String. So
+ // let the chunking be handled by the char[] case.
+ write(new char[] { (char)c }, 0 ,1);
+ }
+ }
+
+ @Override
+ public void println() {
+ write(lineSeparator);
+ }
+
+ @Override
+ public void write(char[] buf, int off, int len) {
+ while (bufferIndex + len > bufferSize) {
+ // Find the next newline in the buffer, see if that's below the limit.
+ // Repeat.
+ int nextNewLine = -1;
+ int maxLength = bufferSize - bufferIndex;
+ for (int i = 0; i < maxLength; i++) {
+ if (buf[off + i] == '\n') {
+ if (bufferIndex + i < bufferSize) {
+ nextNewLine = i;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (nextNewLine != -1) {
+ // We can add some more data.
+ appendToBuffer(buf, off, nextNewLine);
+ writeBuffer(bufferIndex);
+ bufferIndex = 0;
+ lastNewline = -1;
+ off += nextNewLine + 1;
+ len -= nextNewLine + 1;
+ } else if (lastNewline != -1) {
+ // Use the last newline.
+ writeBuffer(lastNewline);
+ removeFromBuffer(lastNewline + 1);
+ lastNewline = -1;
+ } else {
+ // OK, there was no newline, break at a full buffer.
+ int rest = bufferSize - bufferIndex;
+ appendToBuffer(buf, off, rest);
+ writeBuffer(bufferIndex);
+ bufferIndex = 0;
+ off += rest;
+ len -= rest;
+ }
+ }
+
+ // Add to the buffer, this will fit.
+ if (len > 0) {
+ // Add the chars, find the last newline.
+ appendToBuffer(buf, off, len);
+ for (int i = len - 1; i >= 0; i--) {
+ if (buf[off + i] == '\n') {
+ lastNewline = bufferIndex - len + i;
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void write(String s, int off, int len) {
+ while (bufferIndex + len > bufferSize) {
+ // Find the next newline in the buffer, see if that's below the limit.
+ // Repeat.
+ int nextNewLine = -1;
+ int maxLength = bufferSize - bufferIndex;
+ for (int i = 0; i < maxLength; i++) {
+ if (s.charAt(off + i) == '\n') {
+ if (bufferIndex + i < bufferSize) {
+ nextNewLine = i;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (nextNewLine != -1) {
+ // We can add some more data.
+ appendToBuffer(s, off, nextNewLine);
+ writeBuffer(bufferIndex);
+ bufferIndex = 0;
+ lastNewline = -1;
+ off += nextNewLine + 1;
+ len -= nextNewLine + 1;
+ } else if (lastNewline != -1) {
+ // Use the last newline.
+ writeBuffer(lastNewline);
+ removeFromBuffer(lastNewline + 1);
+ lastNewline = -1;
+ } else {
+ // OK, there was no newline, break at a full buffer.
+ int rest = bufferSize - bufferIndex;
+ appendToBuffer(s, off, rest);
+ writeBuffer(bufferIndex);
+ bufferIndex = 0;
+ off += rest;
+ len -= rest;
+ }
+ }
+
+ // Add to the buffer, this will fit.
+ if (len > 0) {
+ // Add the chars, find the last newline.
+ appendToBuffer(s, off, len);
+ for (int i = len - 1; i >= 0; i--) {
+ if (s.charAt(off + i) == '\n') {
+ lastNewline = bufferIndex - len + i;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Append the characters to the buffer. This will potentially resize the buffer,
+ * and move the index along.
+ * @param buf The char[] containing the data.
+ * @param off The start index to copy from.
+ * @param len The number of characters to copy.
+ */
+ private void appendToBuffer(char[] buf, int off, int len) {
+ if (bufferIndex + len > buffer.length) {
+ ensureCapacity(bufferIndex + len);
+ }
+ System.arraycopy(buf, off, buffer, bufferIndex, len);
+ bufferIndex += len;
+ }
+
+ /**
+ * Append the characters from the given string to the buffer. This will potentially
+ * resize the buffer, and move the index along.
+ * @param s The string supplying the characters.
+ * @param off The start index to copy from.
+ * @param len The number of characters to copy.
+ */
+ private void appendToBuffer(String s, int off, int len) {
+ if (bufferIndex + len > buffer.length) {
+ ensureCapacity(bufferIndex + len);
+ }
+ s.getChars(off, off + len, buffer, bufferIndex);
+ bufferIndex += len;
+ }
+
+ /**
+ * Resize the buffer. We use the usual double-the-size plus constant scheme for
+ * amortized O(1) insert. Note: we expect small buffers, so this won't check for
+ * overflow.
+ * @param capacity The size to be ensured.
+ */
+ private void ensureCapacity(int capacity) {
+ int newSize = buffer.length * 2 + 2;
+ if (newSize < capacity) {
+ newSize = capacity;
+ }
+ buffer = Arrays.copyOf(buffer, newSize);
+ }
+
+ /**
+ * Remove the characters up to (and excluding) index i from the buffer. This will
+ * not resize the buffer, but will update bufferIndex.
+ * @param i The number of characters to remove from the front.
+ */
+ private void removeFromBuffer(int i) {
+ int rest = bufferIndex - i;
+ if (rest > 0) {
+ System.arraycopy(buffer, bufferIndex - rest, buffer, 0, rest);
+ bufferIndex = rest;
+ } else {
+ bufferIndex = 0;
+ }
+ }
+
+ /**
+ * Helper method, write the given part of the buffer, [start,length), to the output.
+ * @param length The number of characters to flush.
+ */
+ private void writeBuffer(int length) {
+ if (length > 0) {
+ super.write(buffer, 0, length);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 406b487..dc66818 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -779,7 +779,7 @@
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
- if (mSm != null) {
+ if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
@@ -807,7 +807,7 @@
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
- if (mSm != null) {
+ if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
diff --git a/core/java/com/android/internal/view/IDropPermissionHolder.aidl b/core/java/com/android/internal/view/IDropPermissions.aidl
similarity index 86%
rename from core/java/com/android/internal/view/IDropPermissionHolder.aidl
rename to core/java/com/android/internal/view/IDropPermissions.aidl
index e60ab0e..2438bda 100644
--- a/core/java/com/android/internal/view/IDropPermissionHolder.aidl
+++ b/core/java/com/android/internal/view/IDropPermissions.aidl
@@ -16,11 +16,13 @@
package com.android.internal.view;
+import android.os.IBinder;
+
/**
* Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
* contained in DragEvent.
*/
-interface IDropPermissionHolder {
- void grant();
- void revoke();
+interface IDropPermissions {
+ void take(IBinder activityToken);
+ void release();
}
diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
index 92e9ea6..7ac0ac3 100644
--- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java
@@ -16,6 +16,8 @@
package com.android.internal.view.menu;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -58,7 +60,7 @@
}
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
mContext = context;
mInflater = LayoutInflater.from(mContext);
mMenu = menu;
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index e9b8447..320de90 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -3,6 +3,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import android.annotation.AttrRes;
@@ -36,6 +37,7 @@
import android.widget.PopupWindow.OnDismissListener;
import android.widget.TextView;
+import com.android.internal.R;
import com.android.internal.util.Preconditions;
/**
@@ -45,6 +47,7 @@
*/
final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener,
PopupWindow.OnDismissListener {
+
@Retention(RetentionPolicy.SOURCE)
@IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
public @interface HorizPosition {}
@@ -65,11 +68,14 @@
private final boolean mOverflowOnly;
private final Handler mSubMenuHoverHandler;
+ /** List of menus that were added before this popup was shown. */
+ private final List<MenuBuilder> mPendingMenus = new LinkedList<>();
+
/**
* List of open menus. The first item is the root menu and each
* subsequent item is a direct submenu of the previous item.
*/
- private final List<CascadingMenuInfo> mAddedMenus = new ArrayList<>();
+ private final List<CascadingMenuInfo> mShowingMenus = new ArrayList<>();
private final OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutListener() {
@Override
@@ -80,7 +86,7 @@
dismiss();
} else if (isShowing()) {
// Recompute window sizes and positions.
- for (CascadingMenuInfo info : mAddedMenus) {
+ for (CascadingMenuInfo info : mShowingMenus) {
info.window.show();
}
}
@@ -123,8 +129,8 @@
// Find the position of the hovered menu within the added menus.
int menuIndex = -1;
- for (int i = 0, count = mAddedMenus.size(); i < count; i++) {
- if (menu == mAddedMenus.get(i).menu) {
+ for (int i = 0, count = mShowingMenus.size(); i < count; i++) {
+ if (menu == mShowingMenus.get(i).menu) {
menuIndex = i;
break;
}
@@ -136,8 +142,8 @@
final CascadingMenuInfo nextInfo;
final int nextIndex = menuIndex + 1;
- if (nextIndex < mAddedMenus.size()) {
- nextInfo = mAddedMenus.get(nextIndex);
+ if (nextIndex < mShowingMenus.size()) {
+ nextInfo = mShowingMenus.get(nextIndex);
} else {
nextInfo = null;
}
@@ -228,35 +234,14 @@
return;
}
- // Show any menus that have been added via #addMenu(MenuBuilder) but
- // which have not yet been shown. In a typical use case,
- // #addMenu(MenuBuilder) would be called once, followed by a call to
- // this #show() method -- which would actually show the popup on the
- // screen.
- for (int i = 0, count = mAddedMenus.size(); i < count; i++) {
- final CascadingMenuInfo info = mAddedMenus.get(i);
- final MenuPopupWindow popupWindow = info.window;
- popupWindow.show();
-
- final MenuBuilder menu = info.menu;
- if (i == 0 && mShowTitle && menu.getHeaderTitle() != null) {
- FrameLayout titleItemView =
- (FrameLayout) LayoutInflater.from(mContext).inflate(
- com.android.internal.R.layout.popup_menu_header_item_layout,
- info.getListView(),
- false);
- TextView titleView = (TextView) titleItemView.findViewById(
- com.android.internal.R.id.title);
- titleView.setText(menu.getHeaderTitle());
- titleItemView.setEnabled(false);
- info.getListView().addHeaderView(titleItemView, null, false);
-
- // Update to show the title.
- popupWindow.show();
- }
+ // Display all pending menus.
+ for (MenuBuilder menu : mPendingMenus) {
+ showMenu(menu);
}
+ mPendingMenus.clear();
mShownAnchorView = mAnchorView;
+
if (mShownAnchorView != null) {
final boolean addGlobalListener = mTreeObserver == null;
mTreeObserver = mShownAnchorView.getViewTreeObserver(); // Refresh to latest
@@ -273,10 +258,10 @@
// exception, as #onDismiss may clear mPopupWindows while we are
// iterating. Remove from the last added menu so that the callbacks
// are received in order from foreground to background.
- final int length = mAddedMenus.size();
+ final int length = mShowingMenus.size();
if (length > 0) {
final CascadingMenuInfo[] addedMenus =
- mAddedMenus.toArray(new CascadingMenuInfo[length]);
+ mShowingMenus.toArray(new CascadingMenuInfo[length]);
for (int i = length - 1; i >= 0; i--) {
final CascadingMenuInfo info = addedMenus[i];
if (info.window.isShowing()) {
@@ -315,7 +300,7 @@
*/
@HorizPosition
private int getNextMenuPosition(int nextMenuWidth) {
- ListView lastListView = mAddedMenus.get(mAddedMenus.size() - 1).getListView();
+ ListView lastListView = mShowingMenus.get(mShowingMenus.size() - 1).getListView();
final int[] screenLocation = new int[2];
lastListView.getLocationOnScreen(screenLocation);
@@ -342,6 +327,19 @@
public void addMenu(MenuBuilder menu) {
menu.addMenuPresenter(this, mContext);
+ if (isShowing()) {
+ showMenu(menu);
+ } else {
+ mPendingMenus.add(menu);
+ }
+ }
+
+ /**
+ * Prepares and shows the specified menu immediately.
+ *
+ * @param menu the menu to show
+ */
+ private void showMenu(@NonNull MenuBuilder menu) {
final LayoutInflater inflater = LayoutInflater.from(mContext);
final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly);
adapter.setForceShowIcon(mForceShowIcon);
@@ -354,8 +352,8 @@
final CascadingMenuInfo parentInfo;
final View parentView;
- if (mAddedMenus.size() > 0) {
- parentInfo = mAddedMenus.get(mAddedMenus.size() - 1);
+ if (mShowingMenus.size() > 0) {
+ parentInfo = mShowingMenus.get(mShowingMenus.size() - 1);
parentView = findParentViewForSubmenu(parentInfo, menu);
} else {
parentInfo = null;
@@ -407,12 +405,21 @@
popupWindow.setVerticalOffset(y);
final CascadingMenuInfo menuInfo = new CascadingMenuInfo(popupWindow, menu, mLastPosition);
- mAddedMenus.add(menuInfo);
+ mShowingMenus.add(menuInfo);
- // NOTE: This case handles showing submenus once the CascadingMenuPopup has already
- // been shown via a call to its #show() method. If it hasn't yet been show()n, then
- // we deliberately do not yet show the popupWindow, as #show() will do that later.
- if (isShowing()) {
+ popupWindow.show();
+
+ // If this is the root menu, show the title if requested.
+ if (parentInfo == null && mShowTitle && menu.getHeaderTitle() != null) {
+ final ListView listView = popupWindow.getListView();
+ final FrameLayout titleItemView = (FrameLayout) inflater.inflate(
+ R.layout.popup_menu_header_item_layout, listView, false);
+ final TextView titleView = (TextView) titleItemView.findViewById(R.id.title);
+ titleItemView.setEnabled(false);
+ titleView.setText(menu.getHeaderTitle());
+ listView.addHeaderView(titleItemView, null, false);
+
+ // Show again to update the title.
popupWindow.show();
}
}
@@ -500,7 +507,7 @@
*/
@Override
public boolean isShowing() {
- return mAddedMenus.size() > 0 && mAddedMenus.get(0).window.isShowing();
+ return mShowingMenus.size() > 0 && mShowingMenus.get(0).window.isShowing();
}
/**
@@ -511,8 +518,8 @@
// The dismiss listener doesn't pass the calling window, so walk
// through the stack to figure out which one was just dismissed.
CascadingMenuInfo dismissedInfo = null;
- for (int i = 0, count = mAddedMenus.size(); i < count; i++) {
- final CascadingMenuInfo info = mAddedMenus.get(i);
+ for (int i = 0, count = mShowingMenus.size(); i < count; i++) {
+ final CascadingMenuInfo info = mShowingMenus.get(i);
if (!info.window.isShowing()) {
dismissedInfo = info;
break;
@@ -528,7 +535,7 @@
@Override
public void updateMenuView(boolean cleared) {
- for (CascadingMenuInfo info : mAddedMenus) {
+ for (CascadingMenuInfo info : mShowingMenus) {
toMenuAdapter(info.getListView().getAdapter()).notifyDataSetChanged();
}
}
@@ -541,7 +548,7 @@
@Override
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
// Don't allow double-opening of the same submenu.
- for (CascadingMenuInfo info : mAddedMenus) {
+ for (CascadingMenuInfo info : mShowingMenus) {
if (subMenu == info.menu) {
// Just re-focus that one.
info.getListView().requestFocus();
@@ -567,8 +574,8 @@
* @return the index of the menu, or {@code -1} if not present
*/
private int findIndexOfAddedMenu(@NonNull MenuBuilder menu) {
- for (int i = 0, count = mAddedMenus.size(); i < count; i++) {
- final CascadingMenuInfo info = mAddedMenus.get(i);
+ for (int i = 0, count = mShowingMenus.size(); i < count; i++) {
+ final CascadingMenuInfo info = mShowingMenus.get(i);
if (menu == info.menu) {
return i;
}
@@ -586,13 +593,13 @@
// Recursively close descendant menus.
final int nextMenuIndex = menuIndex + 1;
- if (nextMenuIndex < mAddedMenus.size()) {
- final CascadingMenuInfo childInfo = mAddedMenus.get(nextMenuIndex);
+ if (nextMenuIndex < mShowingMenus.size()) {
+ final CascadingMenuInfo childInfo = mShowingMenus.get(nextMenuIndex);
childInfo.menu.close(false /* closeAllMenus */);
}
// Close the target menu.
- final CascadingMenuInfo info = mAddedMenus.remove(menuIndex);
+ final CascadingMenuInfo info = mShowingMenus.remove(menuIndex);
info.menu.removeMenuPresenter(this);
if (mShouldCloseImmediately) {
// Disable all exit animations.
@@ -601,9 +608,9 @@
}
info.window.dismiss();
- final int count = mAddedMenus.size();
+ final int count = mShowingMenus.size();
if (count > 0) {
- mLastPosition = mAddedMenus.get(count - 1).position;
+ mLastPosition = mShowingMenus.get(count - 1).position;
} else {
mLastPosition = getInitialMenuPosition();
}
@@ -631,7 +638,7 @@
// Close all menus starting from the root. This will recursively
// close any remaining menus, so we don't need to propagate the
// "closeAllMenus" flag. The last window will clean up.
- final CascadingMenuInfo rootInfo = mAddedMenus.get(0);
+ final CascadingMenuInfo rootInfo = mShowingMenus.get(0);
rootInfo.menu.close(false /* closeAllMenus */);
}
}
@@ -677,7 +684,7 @@
@Override
public ListView getListView() {
- return mAddedMenus.isEmpty() ? null : mAddedMenus.get(mAddedMenus.size() - 1).getListView();
+ return mShowingMenus.isEmpty() ? null : mShowingMenus.get(mShowingMenus.size() - 1).getListView();
}
@Override
diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
index 2439b5d..5223a7b 100644
--- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java
@@ -17,6 +17,8 @@
import com.android.internal.view.menu.MenuView.ItemView;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
@@ -49,7 +51,7 @@
}
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
super.initForMenu(context, menu);
mMaxItems = -1;
}
diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
index c476354..2fff3ba 100644
--- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java
@@ -16,6 +16,8 @@
package com.android.internal.view.menu;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
@@ -76,7 +78,7 @@
}
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
if (mThemeRes != 0) {
mContext = new ContextThemeWrapper(context, mThemeRes);
mInflater = LayoutInflater.from(mContext);
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 465d775..31b2f96 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -17,6 +17,7 @@
package com.android.internal.view.menu;
+import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -1027,23 +1028,24 @@
mIsActionItemsStale = true;
onItemsChanged(true);
}
-
+
+ @NonNull
public ArrayList<MenuItemImpl> getVisibleItems() {
if (!mIsVisibleItemsStale) return mVisibleItems;
-
+
// Refresh the visible items
mVisibleItems.clear();
-
+
final int itemsSize = mItems.size();
MenuItemImpl item;
for (int i = 0; i < itemsSize; i++) {
item = mItems.get(i);
if (item.isVisible()) mVisibleItems.add(item);
}
-
+
mIsVisibleItemsStale = false;
mIsActionItemsStale = true;
-
+
return mVisibleItems;
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 98f5d90..b151f34 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -16,6 +16,8 @@
package com.android.internal.view.menu;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.view.MenuItem;
import android.view.View;
@@ -73,7 +75,7 @@
public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener);
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
// Don't need to do anything; we added as a presenter in the constructor.
}
diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java
index c847c15..65bdc09 100644
--- a/core/java/com/android/internal/view/menu/MenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/MenuPresenter.java
@@ -16,6 +16,8 @@
package com.android.internal.view.menu;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.Parcelable;
import android.view.ViewGroup;
@@ -49,14 +51,16 @@
}
/**
- * Initialize this presenter for the given context and menu.
- * This method is called by MenuBuilder when a presenter is
- * added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
+ * Initializes this presenter for the given context and menu.
+ * <p>
+ * This method is called by MenuBuilder when a presenter is added. See
+ * {@link MenuBuilder#addMenuPresenter(MenuPresenter)}.
*
- * @param context Context for this presenter; used for view creation and resource management
- * @param menu Menu to host
+ * @param context the context for this presenter; used for view creation
+ * and resource management, must be non-{@code null}
+ * @param menu the menu to host, or {@code null} to clear the hosted menu
*/
- public void initForMenu(Context context, MenuBuilder menu);
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu);
/**
* Retrieve a MenuView to display the menu specified in
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 6a5f6d8..c2adc42 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -242,13 +242,13 @@
@Override
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
if (subMenu.hasVisibleItems()) {
- MenuPopupHelper subPopup = new MenuPopupHelper(
- mContext, subMenu, mShownAnchorView, mOverflowOnly, mPopupStyleAttr,
- mPopupStyleRes);
+ final MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu,
+ mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
subPopup.setPresenterCallback(mPresenterCallback);
subPopup.setForceShowIcon(mAdapter.getForceShowIcon());
- if (subPopup.tryShow()) {
+ // Show the new sub-menu popup at the same location as this popup.
+ if (subPopup.tryShow(mXOffset, mYOffset)) {
if (mPresenterCallback != null) {
mPresenterCallback.onOpenSubMenu(subMenu);
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 825e336..f90b59d 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -17,6 +17,8 @@
package com.android.internal.widget;
import android.animation.LayoutTransition;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActionBar;
import android.content.Context;
import android.content.res.Configuration;
@@ -1593,7 +1595,7 @@
MenuItemImpl mCurrentExpandedItem;
@Override
- public void initForMenu(Context context, MenuBuilder menu) {
+ public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
// Clear the expanded action view when menus change.
if (mMenu != null && mCurrentExpandedItem != null) {
mMenu.collapseItemActionView(mCurrentExpandedItem);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index bdbd096..30593f2 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -43,11 +43,13 @@
android_opengl_GLES30.cpp \
android_opengl_GLES31.cpp \
android_opengl_GLES31Ext.cpp \
+ android_opengl_GLES32.cpp \
android_database_CursorWindow.cpp \
android_database_SQLiteCommon.cpp \
android_database_SQLiteConnection.cpp \
android_database_SQLiteGlobal.cpp \
android_database_SQLiteDebug.cpp \
+ android_graphics_drawable_VectorDrawable.cpp \
android_view_DisplayEventReceiver.cpp \
android_view_DisplayListCanvas.cpp \
android_view_GraphicBuffer.cpp \
@@ -96,7 +98,6 @@
android_util_jar_StrictJarFile.cpp \
android_graphics_Canvas.cpp \
android_graphics_Picture.cpp \
- android/graphics/AutoDecodeCancel.cpp \
android/graphics/AvoidXfermode.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
@@ -185,6 +186,8 @@
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(TOP)/frameworks/av/include \
$(TOP)/frameworks/base/media/jni \
+ $(TOP)/system/core/base/include \
+ $(TOP)/system/core/include \
$(TOP)/system/media/camera/include \
$(TOP)/system/netd/include \
external/pdfium/core/include/fpdfapi \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f6f45b5..63f193d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -80,6 +80,7 @@
extern int register_android_opengl_jni_GLES30(JNIEnv* env);
extern int register_android_opengl_jni_GLES31(JNIEnv* env);
extern int register_android_opengl_jni_GLES31Ext(JNIEnv* env);
+extern int register_android_opengl_jni_GLES32(JNIEnv* env);
extern int register_android_hardware_Camera(JNIEnv *env);
extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env);
@@ -129,6 +130,7 @@
extern int register_android_graphics_Region(JNIEnv* env);
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
+extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
@@ -1280,6 +1282,7 @@
REG_JNI(register_android_opengl_jni_GLES30),
REG_JNI(register_android_opengl_jni_GLES31),
REG_JNI(register_android_opengl_jni_GLES31Ext),
+ REG_JNI(register_android_opengl_jni_GLES32),
REG_JNI(register_android_graphics_Bitmap),
REG_JNI(register_android_graphics_BitmapFactory),
@@ -1310,6 +1313,7 @@
REG_JNI(register_android_graphics_Typeface),
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
+ REG_JNI(register_android_graphics_drawable_VectorDrawable),
REG_JNI(register_android_graphics_pdf_PdfDocument),
REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
diff --git a/core/jni/android/graphics/AutoDecodeCancel.cpp b/core/jni/android/graphics/AutoDecodeCancel.cpp
deleted file mode 100644
index 0641b96..0000000
--- a/core/jni/android/graphics/AutoDecodeCancel.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-#include "AutoDecodeCancel.h"
-#include "SkMutex.h"
-
-SK_DECLARE_STATIC_MUTEX(gAutoDecoderCancelMutex);
-static AutoDecoderCancel* gAutoDecoderCancel;
-#ifdef SK_DEBUG
-static int gAutoDecoderCancelCount;
-#endif
-
-AutoDecoderCancel::AutoDecoderCancel(jobject joptions,
- SkImageDecoder* decoder) {
- fJOptions = joptions;
- fDecoder = decoder;
-
- if (NULL != joptions) {
- SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
-
- // Add us as the head of the list
- fPrev = NULL;
- fNext = gAutoDecoderCancel;
- if (gAutoDecoderCancel) {
- gAutoDecoderCancel->fPrev = this;
- }
- gAutoDecoderCancel = this;
-
- SkDEBUGCODE(gAutoDecoderCancelCount += 1;)
- Validate();
- }
-}
-
-AutoDecoderCancel::~AutoDecoderCancel() {
- if (NULL != fJOptions) {
- SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
-
- // take us out of the dllist
- AutoDecoderCancel* prev = fPrev;
- AutoDecoderCancel* next = fNext;
-
- if (prev) {
- SkASSERT(prev->fNext == this);
- prev->fNext = next;
- } else {
- SkASSERT(gAutoDecoderCancel == this);
- gAutoDecoderCancel = next;
- }
- if (next) {
- SkASSERT(next->fPrev == this);
- next->fPrev = prev;
- }
-
- SkDEBUGCODE(gAutoDecoderCancelCount -= 1;)
- Validate();
- }
-}
-
-bool AutoDecoderCancel::RequestCancel(jobject joptions) {
- SkAutoMutexAcquire ac(gAutoDecoderCancelMutex);
-
- Validate();
-
- AutoDecoderCancel* pair = gAutoDecoderCancel;
- while (pair != NULL) {
- if (pair->fJOptions == joptions) {
- pair->fDecoder->cancelDecode();
- return true;
- }
- pair = pair->fNext;
- }
- return false;
-}
-
-#ifdef SK_DEBUG
-// can only call this inside a lock on gAutoDecoderCancelMutex
-void AutoDecoderCancel::Validate() {
- const int gCount = gAutoDecoderCancelCount;
-
- if (gCount == 0) {
- SkASSERT(gAutoDecoderCancel == NULL);
- } else {
- SkASSERT(gCount > 0);
-
- AutoDecoderCancel* curr = gAutoDecoderCancel;
- SkASSERT(curr);
- SkASSERT(curr->fPrev == NULL);
-
- int count = 0;
- while (curr) {
- count += 1;
- SkASSERT(count <= gCount);
- if (curr->fPrev) {
- SkASSERT(curr->fPrev->fNext == curr);
- }
- if (curr->fNext) {
- SkASSERT(curr->fNext->fPrev == curr);
- }
- curr = curr->fNext;
- }
- SkASSERT(count == gCount);
- }
-}
-#endif
diff --git a/core/jni/android/graphics/AutoDecodeCancel.h b/core/jni/android/graphics/AutoDecodeCancel.h
deleted file mode 100644
index dd6a0d4..0000000
--- a/core/jni/android/graphics/AutoDecodeCancel.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
-#define _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
-
-#include <jni.h>
-#include "SkImageDecoder.h"
-
-class AutoDecoderCancel {
-public:
- AutoDecoderCancel(jobject options, SkImageDecoder* decoder);
- ~AutoDecoderCancel();
-
- static bool RequestCancel(jobject options);
-
-private:
- AutoDecoderCancel* fNext;
- AutoDecoderCancel* fPrev;
- jobject fJOptions; // java options object
- SkImageDecoder* fDecoder;
-
-#ifdef SK_DEBUG
- static void Validate();
-#else
- static void Validate() {}
-#endif
-};
-
-#endif // _ANDROID_GRAPHICS_AUTO_DECODE_CANCEL_H_
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index ecaf951..92f7812 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -1,10 +1,11 @@
#define LOG_TAG "BitmapFactory"
-#include "AutoDecodeCancel.h"
#include "BitmapFactory.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "GraphicsJNI.h"
#include "NinePatchPeeker.h"
+#include "SkAndroidCodec.h"
+#include "SkBRDAllocator.h"
#include "SkFrontBufferedStream.h"
#include "SkImageDecoder.h"
#include "SkMath.h"
@@ -48,41 +49,44 @@
using namespace android;
-jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
- static const struct {
- SkImageDecoder::Format fFormat;
- const char* fMimeType;
- } gMimeTypes[] = {
- { SkImageDecoder::kBMP_Format, "image/bmp" },
- { SkImageDecoder::kGIF_Format, "image/gif" },
- { SkImageDecoder::kICO_Format, "image/x-ico" },
- { SkImageDecoder::kJPEG_Format, "image/jpeg" },
- { SkImageDecoder::kPNG_Format, "image/png" },
- { SkImageDecoder::kWEBP_Format, "image/webp" },
- { SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
- };
-
- const char* cstr = nullptr;
- for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
- if (gMimeTypes[i].fFormat == format) {
- cstr = gMimeTypes[i].fMimeType;
+jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format) {
+ const char* mimeType;
+ switch (format) {
+ case SkEncodedFormat::kBMP_SkEncodedFormat:
+ mimeType = "image/bmp";
break;
- }
+ case SkEncodedFormat::kGIF_SkEncodedFormat:
+ mimeType = "image/gif";
+ break;
+ case SkEncodedFormat::kICO_SkEncodedFormat:
+ mimeType = "image/x-ico";
+ break;
+ case SkEncodedFormat::kJPEG_SkEncodedFormat:
+ mimeType = "image/jpeg";
+ break;
+ case SkEncodedFormat::kPNG_SkEncodedFormat:
+ mimeType = "image/png";
+ break;
+ case SkEncodedFormat::kWEBP_SkEncodedFormat:
+ mimeType = "image/webp";
+ break;
+ case SkEncodedFormat::kWBMP_SkEncodedFormat:
+ mimeType = "image/vnd.wap.wbmp";
+ break;
+ default:
+ mimeType = nullptr;
+ break;
}
jstring jstr = nullptr;
- if (cstr != nullptr) {
+ if (mimeType) {
// NOTE: Caller should env->ExceptionCheck() for OOM
// (can't check for nullptr as it's a valid return value)
- jstr = env->NewStringUTF(cstr);
+ jstr = env->NewStringUTF(mimeType);
}
return jstr;
}
-static bool optionsJustBounds(JNIEnv* env, jobject options) {
- return options != NULL && env->GetBooleanField(options, gOptions_justBoundsFieldID);
-}
-
static void scaleDivRange(int32_t* divs, int count, float scale, int maxValue) {
for (int i = 0; i < count; i++) {
divs[i] = int32_t(divs[i] * scale + 0.5f);
@@ -198,24 +202,32 @@
};
static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
+ // This function takes ownership of the input stream. Since the SkAndroidCodec
+ // will take ownership of the stream, we don't necessarily need to take ownership
+ // here. This is a precaution - if we were to return before creating the codec,
+ // we need to make sure that we delete the stream.
+ std::unique_ptr<SkStreamRewindable> streamDeleter(stream);
+ // Set default values for the options parameters.
int sampleSize = 1;
-
- SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode;
+ bool onlyDecodeSize = false;
SkColorType prefColorType = kN32_SkColorType;
-
- bool doDither = true;
bool isMutable = false;
float scale = 1.0f;
- bool preferQualityOverSpeed = false;
bool requireUnpremultiplied = false;
-
jobject javaBitmap = NULL;
+ // Update with options supplied by the client.
if (options != NULL) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
- if (optionsJustBounds(env, options)) {
- decodeMode = SkImageDecoder::kDecodeBounds_Mode;
+ // Correct a non-positive sampleSize. sampleSize defaults to zero within the
+ // options object, which is strange.
+ if (sampleSize <= 0) {
+ sampleSize = 1;
+ }
+
+ if (env->GetBooleanField(options, gOptions_justBoundsFieldID)) {
+ onlyDecodeSize = true;
}
// initialize these, in case we fail later on
@@ -226,9 +238,6 @@
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
- doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
- preferQualityOverSpeed = env->GetBooleanField(options,
- gOptions_preferQualityOverSpeedFieldID);
requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
@@ -241,18 +250,40 @@
}
}
}
-
const bool willScale = scale != 1.0f;
- SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
- if (decoder == NULL) {
- return nullObjectReturn("SkImageDecoder::Factory returned null");
+ // Create the codec.
+ NinePatchPeeker peeker;
+ std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(),
+ &peeker));
+ if (!codec.get()) {
+ return nullObjectReturn("SkAndroidCodec::NewFromStream returned null");
}
- decoder->setSampleSize(sampleSize);
- decoder->setDitherImage(doDither);
- decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
- decoder->setRequireUnpremultipliedColors(requireUnpremultiplied);
+ // Do not allow ninepatch decodes to 565. In the past, decodes to 565
+ // would dither, and we do not want to pre-dither ninepatches, since we
+ // know that they will be stretched. We no longer dither 565 decodes,
+ // but we continue to prevent ninepatches from decoding to 565, in order
+ // to maintain the old behavior.
+ if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) {
+ prefColorType = kN32_SkColorType;
+ }
+
+ // Determine the output size and return if the client only wants the size.
+ SkISize size = codec->getSampledDimensions(sampleSize);
+ if (options != NULL) {
+ jstring mimeType = encodedFormatToString(env, codec->getEncodedFormat());
+ if (env->ExceptionCheck()) {
+ return nullObjectReturn("OOM in encodedFormatToString()");
+ }
+ env->SetIntField(options, gOptions_widthFieldID, size.width());
+ env->SetIntField(options, gOptions_heightFieldID, size.height());
+ env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
+
+ if (onlyDecodeSize) {
+ return nullptr;
+ }
+ }
android::Bitmap* reuseBitmap = nullptr;
unsigned int existingBufferSize = 0;
@@ -267,71 +298,96 @@
}
}
- NinePatchPeeker peeker(decoder);
- decoder->setPeeker(&peeker);
-
JavaPixelAllocator javaAllocator(env);
RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
- SkBitmap::Allocator* outputAllocator = (javaBitmap != NULL) ?
- (SkBitmap::Allocator*)&recyclingAllocator : (SkBitmap::Allocator*)&javaAllocator;
- if (decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
- if (!willScale) {
- // If the java allocator is being used to allocate the pixel memory, the decoder
- // need not write zeroes, since the memory is initialized to 0.
- decoder->setSkipWritingZeroes(outputAllocator == &javaAllocator);
- decoder->setAllocator(outputAllocator);
- } else if (javaBitmap != NULL) {
- // check for eventual scaled bounds at allocation time, so we don't decode the bitmap
- // only to find the scaled result too large to fit in the allocation
- decoder->setAllocator(&scaleCheckingAllocator);
- }
+ SkBitmap::HeapAllocator heapAllocator;
+ SkBitmap::Allocator* decodeAllocator;
+ if (javaBitmap != nullptr && willScale) {
+ // This will allocate pixels using a HeapAllocator, since there will be an extra
+ // scaling step that copies these pixels into Java memory. This allocator
+ // also checks that the recycled javaBitmap is large enough.
+ decodeAllocator = &scaleCheckingAllocator;
+ } else if (javaBitmap != nullptr) {
+ decodeAllocator = &recyclingAllocator;
+ } else if (willScale) {
+ // This will allocate pixels using a HeapAllocator, since there will be an extra
+ // scaling step that copies these pixels into Java memory.
+ decodeAllocator = &heapAllocator;
+ } else {
+ decodeAllocator = &javaAllocator;
}
- // Only setup the decoder to be deleted after its stack-based, refcounted
- // components (allocators, peekers, etc) are declared. This prevents RefCnt
- // asserts from firing due to the order objects are deleted from the stack.
- std::unique_ptr<SkImageDecoder> add(decoder);
+ // Set the decode colorType. This is necessary because we can't always support
+ // the requested colorType.
+ SkColorType decodeColorType = codec->computeOutputColorType(prefColorType);
- AutoDecoderCancel adc(options, decoder);
+ // Construct a color table for the decode if necessary
+ SkAutoTUnref<SkColorTable> colorTable(nullptr);
+ SkPMColor* colorPtr = nullptr;
+ int* colorCount = nullptr;
+ int maxColors = 256;
+ SkPMColor colors[256];
+ if (kIndex_8_SkColorType == decodeColorType) {
+ colorTable.reset(new SkColorTable(colors, maxColors));
- // To fix the race condition in case "requestCancelDecode"
- // happens earlier than AutoDecoderCancel object is added
- // to the gAutoDecoderCancelMutex linked list.
- if (options != NULL && env->GetBooleanField(options, gOptions_mCancelID)) {
- return nullObjectReturn("gOptions_mCancelID");
+ // SkColorTable expects us to initialize all of the colors before creating an
+ // SkColorTable. However, we are using SkBitmap with an Allocator to allocate
+ // memory for the decode, so we need to create the SkColorTable before decoding.
+ // It is safe for SkAndroidCodec to modify the colors because this SkBitmap is
+ // not being used elsewhere.
+ colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
+ colorCount = &maxColors;
}
+ // Set the alpha type for the decode.
+ SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
+
+ const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType,
+ alphaType);
+ SkImageInfo bitmapInfo = decodeInfo;
+ if (decodeColorType == kGray_8_SkColorType) {
+ // The legacy implementation of BitmapFactory used kAlpha8 for
+ // grayscale images (before kGray8 existed). While the codec
+ // recognizes kGray8, we need to decode into a kAlpha8 bitmap
+ // in order to avoid a behavior change.
+ bitmapInfo = SkImageInfo::MakeA8(size.width(), size.height());
+ }
SkBitmap decodingBitmap;
- if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)
- != SkImageDecoder::kSuccess) {
- return nullObjectReturn("decoder->decode returned false");
+ if (!decodingBitmap.setInfo(bitmapInfo) ||
+ !decodingBitmap.tryAllocPixels(decodeAllocator, colorTable)) {
+ // SkAndroidCodec should recommend a valid SkImageInfo, so setInfo()
+ // should only only fail if the calculated value for rowBytes is too
+ // large.
+ // tryAllocPixels() can fail due to OOM on the Java heap, OOM on the
+ // native heap, or the recycled javaBitmap being too small to reuse.
+ return nullptr;
}
- int scaledWidth = decodingBitmap.width();
- int scaledHeight = decodingBitmap.height();
+ // Use SkAndroidCodec to perform the decode.
+ SkAndroidCodec::AndroidOptions codecOptions;
+ codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ?
+ SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
+ codecOptions.fColorPtr = colorPtr;
+ codecOptions.fColorCount = colorCount;
+ codecOptions.fSampleSize = sampleSize;
+ SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodingBitmap.getPixels(),
+ decodingBitmap.rowBytes(), &codecOptions);
+ switch (result) {
+ case SkCodec::kSuccess:
+ case SkCodec::kIncompleteInput:
+ break;
+ default:
+ return nullObjectReturn("codec->getAndroidPixels() failed.");
+ }
- if (willScale && decodeMode != SkImageDecoder::kDecodeBounds_Mode) {
+ int scaledWidth = size.width();
+ int scaledHeight = size.height();
+ if (willScale) {
scaledWidth = int(scaledWidth * scale + 0.5f);
scaledHeight = int(scaledHeight * scale + 0.5f);
}
- // update options (if any)
- if (options != NULL) {
- jstring mimeType = getMimeTypeString(env, decoder->getFormat());
- if (env->ExceptionCheck()) {
- return nullObjectReturn("OOM in getMimeTypeString()");
- }
- env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
- env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
- env->SetObjectField(options, gOptions_mimeFieldID, mimeType);
- }
-
- // if we're in justBounds mode, return now (skip the java bitmap)
- if (decodeMode == SkImageDecoder::kDecodeBounds_Mode) {
- return NULL;
- }
-
jbyteArray ninePatchChunk = NULL;
if (peeker.mPatch != NULL) {
if (willScale) {
@@ -377,29 +433,36 @@
const float sx = scaledWidth / float(decodingBitmap.width());
const float sy = scaledHeight / float(decodingBitmap.height());
- // TODO: avoid copying when scaled size equals decodingBitmap size
- SkColorType colorType = colorTypeForScaledOutput(decodingBitmap.colorType());
+ // Set the allocator for the outputBitmap.
+ SkBitmap::Allocator* outputAllocator;
+ if (javaBitmap != nullptr) {
+ outputAllocator = &recyclingAllocator;
+ } else {
+ outputAllocator = &javaAllocator;
+ }
+
+ SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType());
// FIXME: If the alphaType is kUnpremul and the image has alpha, the
// colors may not be correct, since Skia does not yet support drawing
// to/from unpremultiplied bitmaps.
outputBitmap.setInfo(SkImageInfo::Make(scaledWidth, scaledHeight,
- colorType, decodingBitmap.alphaType()));
+ scaledColorType, decodingBitmap.alphaType()));
if (!outputBitmap.tryAllocPixels(outputAllocator, NULL)) {
+ // This should only fail on OOM. The recyclingAllocator should have
+ // enough memory since we check this before decoding using the
+ // scaleCheckingAllocator.
return nullObjectReturn("allocation failed for scaled bitmap");
}
- // If outputBitmap's pixels are newly allocated by Java, there is no need
- // to erase to 0, since the pixels were initialized to 0.
- if (outputAllocator != &javaAllocator) {
- outputBitmap.eraseColor(0);
- }
-
SkPaint paint;
+ // kSrc_Mode instructs us to overwrite the unininitialized pixels in
+ // outputBitmap. Otherwise we would blend by default, which is not
+ // what we want.
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
paint.setFilterQuality(kLow_SkFilterQuality);
SkCanvas canvas(outputBitmap);
canvas.scale(sx, sy);
- canvas.drawARGB(0x00, 0x00, 0x00, 0x00);
canvas.drawBitmap(decodingBitmap, 0.0f, 0.0f, &paint);
} else {
outputBitmap.swap(decodingBitmap);
@@ -415,8 +478,7 @@
}
}
- // if we get here, we're in kDecodePixels_Mode and will therefore
- // already have a pixelref installed.
+ // If we get here, the outputBitmap should have an installed pixelref.
if (outputBitmap.pixelRef() == NULL) {
return nullObjectReturn("Got null SkPixelRef");
}
@@ -426,8 +488,8 @@
outputBitmap.setImmutable();
}
- if (javaBitmap != NULL) {
- bool isPremultiplied = !requireUnpremultiplied;
+ bool isPremultiplied = !requireUnpremultiplied;
+ if (javaBitmap != nullptr) {
GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
outputBitmap.notifyPixelsChanged();
// If a java bitmap was passed in for reuse, pass it back
@@ -436,7 +498,7 @@
int bitmapCreateFlags = 0x0;
if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
- if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+ if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
// now create the java bitmap
return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),
@@ -445,8 +507,8 @@
// Need to buffer enough input to be able to rewind as much as might be read by a decoder
// trying to determine the stream's format. Currently the most is 64, read by
-// SkImageDecoder_libwebp.
-// FIXME: Get this number from SkImageDecoder
+// SkWebpCodec.
+// FIXME: Get this number from SkCodec
#define BYTES_TO_BUFFER 64
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
@@ -459,7 +521,7 @@
std::unique_ptr<SkStreamRewindable> bufferedStream(
SkFrontBufferedStream::Create(stream.release(), BYTES_TO_BUFFER));
SkASSERT(bufferedStream.get() != NULL);
- bitmap = doDecode(env, bufferedStream.get(), padding, options);
+ bitmap = doDecode(env, bufferedStream.release(), padding, options);
}
return bitmap;
}
@@ -505,7 +567,7 @@
std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Create(fileStream.release(),
BYTES_TO_BUFFER));
- return doDecode(env, stream.get(), padding, bitmapFactoryOptions);
+ return doDecode(env, stream.release(), padding, bitmapFactoryOptions);
}
static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
@@ -514,20 +576,16 @@
Asset* asset = reinterpret_cast<Asset*>(native_asset);
// since we know we'll be done with the asset when we return, we can
// just use a simple wrapper
- AssetStreamAdaptor stream(asset);
- return doDecode(env, &stream, padding, options);
+ std::unique_ptr<AssetStreamAdaptor> stream(new AssetStreamAdaptor(asset));
+ return doDecode(env, stream.release(), padding, options);
}
static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
jint offset, jint length, jobject options) {
AutoJavaByteArray ar(env, byteArray);
- SkMemoryStream stream(ar.ptr() + offset, length, false);
- return doDecode(env, &stream, NULL, options);
-}
-
-static void nativeRequestCancel(JNIEnv*, jobject joptions) {
- (void)AutoDecoderCancel::RequestCancel(joptions);
+ std::unique_ptr<SkMemoryStream> stream(new SkMemoryStream(ar.ptr() + offset, length, false));
+ return doDecode(env, stream.release(), NULL, options);
}
static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
@@ -569,10 +627,6 @@
},
};
-static const JNINativeMethod gOptionsMethods[] = {
- { "requestCancel", "()V", (void*)nativeRequestCancel }
-};
-
int register_android_graphics_BitmapFactory(JNIEnv* env) {
jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
@@ -604,8 +658,6 @@
gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
"(IIIIIIIIFIF)V");
- android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory$Options",
- gOptionsMethods, NELEM(gOptionsMethods));
return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index 22a955f..07825df 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -2,6 +2,7 @@
#define _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
#include "GraphicsJNI.h"
+#include "SkEncodedFormat.h"
extern jclass gOptions_class;
extern jfieldID gOptions_justBoundsFieldID;
@@ -19,7 +20,7 @@
extern jfieldID gOptions_mCancelID;
extern jfieldID gOptions_bitmapFieldID;
-jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format);
+jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format);
jobject decodeBitmap(JNIEnv* env, void* data, size_t size);
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index f10f4bd..a1ba42e 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -25,7 +25,6 @@
#include "SkBitmapRegionDecoder.h"
#include "SkCodec.h"
#include "SkData.h"
-#include "SkEncodedFormat.h"
#include "SkUtils.h"
#include "SkPixelRef.h"
#include "SkStream.h"
@@ -42,43 +41,6 @@
using namespace android;
-// This is very similar to, and based on, getMimeTypeString() in BitmapFactory.
-jstring encodedFormatToString(JNIEnv* env, SkEncodedFormat format) {
- const char* mimeType;
- switch (format) {
- case SkEncodedFormat::kBMP_SkEncodedFormat:
- mimeType = "image/bmp";
- break;
- case SkEncodedFormat::kGIF_SkEncodedFormat:
- mimeType = "image/gif";
- break;
- case SkEncodedFormat::kICO_SkEncodedFormat:
- mimeType = "image/x-ico";
- break;
- case SkEncodedFormat::kJPEG_SkEncodedFormat:
- mimeType = "image/jpeg";
- break;
- case SkEncodedFormat::kPNG_SkEncodedFormat:
- mimeType = "image/png";
- break;
- case SkEncodedFormat::kWEBP_SkEncodedFormat:
- mimeType = "image/webp";
- break;
- case SkEncodedFormat::kWBMP_SkEncodedFormat:
- mimeType = "image/vnd.wap.wbmp";
- break;
- default:
- mimeType = nullptr;
- break;
- }
-
- jstring jstr = nullptr;
- if (mimeType != nullptr) {
- jstr = env->NewStringUTF(mimeType);
- }
- return jstr;
-}
-
// Takes ownership of the SkStreamRewindable. For consistency, deletes stream even
// when returning null.
static jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) {
@@ -174,9 +136,6 @@
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
colorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig);
- if (kAlpha_8_SkColorType == colorType) {
- colorType = kGray_8_SkColorType;
- }
requireUnpremul = !env->GetBooleanField(options, gOptions_premultipliedFieldID);
javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);
// The Java options of ditherMode and preferQualityOverSpeed are deprecated. We will
@@ -227,6 +186,9 @@
env->SetIntField(options, gOptions_heightFieldID, bitmap.height());
env->SetObjectField(options, gOptions_mimeFieldID,
encodedFormatToString(env, brd->getEncodedFormat()));
+ if (env->ExceptionCheck()) {
+ return nullObjectReturn("OOM in encodedFormatToString()");
+ }
}
// If we may have reused a bitmap, we need to indicate that the pixels have changed.
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ab0df55..7c8dbe8 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -36,12 +36,12 @@
namespace android {
static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
- FontLanguage fontLanguage;
- if (lang != NULL) {
- ScopedUtfChars str(env, lang);
- fontLanguage = FontLanguage(str.c_str(), str.size());
+ if (lang == NULL) {
+ return (jlong)new FontFamily(variant);
}
- return (jlong)new FontFamily(fontLanguage, variant);
+ ScopedUtfChars str(env, lang);
+ uint32_t langId = FontStyle::registerLanguageList(str.c_str());
+ return (jlong)new FontFamily(langId, variant);
}
static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
diff --git a/core/jni/android/graphics/NinePatchPeeker.cpp b/core/jni/android/graphics/NinePatchPeeker.cpp
index 6c32a21..8a84a35 100644
--- a/core/jni/android/graphics/NinePatchPeeker.cpp
+++ b/core/jni/android/graphics/NinePatchPeeker.cpp
@@ -17,10 +17,11 @@
#include "NinePatchPeeker.h"
#include "SkBitmap.h"
+#include "SkImageDecoder.h"
using namespace android;
-bool NinePatchPeeker::peek(const char tag[], const void* data, size_t length) {
+bool NinePatchPeeker::readChunk(const char tag[], const void* data, size_t length) {
if (!strcmp("npTc", tag) && length >= sizeof(Res_png_9patch)) {
Res_png_9patch* patch = (Res_png_9patch*) data;
size_t patchSize = patch->serializedSize();
@@ -35,11 +36,6 @@
free(mPatch);
mPatch = patchNew;
mPatchSize = patchSize;
-
- // now update our host to force index or 32bit config
- // 'cause we don't want 565 predithered, since as a 9patch, we know
- // we will be stretched, and therefore we want to dither afterwards.
- mHost->setPreserveSrcDepth(true);
} else if (!strcmp("npLb", tag) && length == sizeof(int32_t) * 4) {
mHasInsets = true;
memcpy(&mOpticalInsets, data, sizeof(int32_t) * 4);
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h
index 2d49b38..126eab2 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/core/jni/android/graphics/NinePatchPeeker.h
@@ -17,19 +17,17 @@
#ifndef _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_
#define _ANDROID_GRAPHICS_NINE_PATCH_PEEKER_H_
-#include "SkImageDecoder.h"
+#include "SkPngChunkReader.h"
#include <androidfw/ResourceTypes.h>
+class SkImageDecoder;
+
using namespace android;
-class NinePatchPeeker : public SkImageDecoder::Peeker {
-private:
- // the host lives longer than we do, so a raw ptr is safe
- SkImageDecoder* mHost;
+class NinePatchPeeker : public SkPngChunkReader {
public:
- NinePatchPeeker(SkImageDecoder* host)
- : mHost(host)
- , mPatch(NULL)
+ NinePatchPeeker()
+ : mPatch(NULL)
, mPatchSize(0)
, mHasInsets(false)
, mOutlineRadius(0)
@@ -42,7 +40,7 @@
free(mPatch);
}
- virtual bool peek(const char tag[], const void* data, size_t length);
+ bool readChunk(const char tag[], const void* data, size_t length) override;
Res_png_9patch* mPatch;
size_t mPatchSize;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 654d148..0a25a0a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -313,94 +313,10 @@
obj->setTextAlign(align);
}
- // generate bcp47 identifier for the supplied locale
- static void toLanguageTag(char* output, size_t outSize,
- const char* locale) {
- if (output == NULL || outSize <= 0) {
- return;
- }
- if (locale == NULL) {
- output[0] = '\0';
- return;
- }
- char canonicalChars[ULOC_FULLNAME_CAPACITY];
- UErrorCode uErr = U_ZERO_ERROR;
- uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
- &uErr);
- if (U_SUCCESS(uErr)) {
- char likelyChars[ULOC_FULLNAME_CAPACITY];
- uErr = U_ZERO_ERROR;
- uloc_addLikelySubtags(canonicalChars, likelyChars,
- ULOC_FULLNAME_CAPACITY, &uErr);
- if (U_SUCCESS(uErr)) {
- uErr = U_ZERO_ERROR;
- uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
- if (U_SUCCESS(uErr)) {
- return;
- } else {
- ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
- u_errorName(uErr));
- }
- } else {
- ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
- canonicalChars, u_errorName(uErr));
- }
- } else {
- ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
- u_errorName(uErr));
- }
- // unable to build a proper language identifier
- output[0] = '\0';
- }
-
- static void toLanguageTags(std::string* output, const char* locales) {
- if (output == NULL) {
- return;
- }
- if (locales == NULL) {
- output->clear();
- return;
- }
-
- char langTag[ULOC_FULLNAME_CAPACITY];
- const char* commaLoc = strchr(locales, ',');
- if (commaLoc == NULL) {
- assert(locales[0] != '\0'); // the string should not be empty
- toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locales);
- *output = langTag;
- return;
- }
-
- size_t len = strlen(locales);
- char locale[len];
- output->clear();
- output->reserve(len);
- const char* lastStart = locales;
- do {
- assert(lastStart > commaLoc); // the substring should not be empty
- strncpy(locale, lastStart, commaLoc - lastStart);
- locale[commaLoc - lastStart] = '\0';
- toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale);
- if (langTag[0] != '\0') {
- output->append(langTag);
- output->push_back(',');
- }
- lastStart = commaLoc + 1;
- commaLoc = strchr(lastStart, ',');
- } while (commaLoc != NULL);
- assert(lastStart[0] != '\0'); // the final substring should not be empty
- toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, lastStart);
- if (langTag[0] != '\0') {
- output->append(langTag);
- }
- }
-
static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
ScopedUtfChars localesChars(env, locales);
- std::string buf;
- toLanguageTags(&buf, localesChars.c_str());
- jint minikinLangListId = FontStyle::registerLanguageList(buf);
+ jint minikinLangListId = FontStyle::registerLanguageList(localesChars.c_str());
obj->setMinikinLangListId(minikinLangListId);
return minikinLangListId;
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 6ecb3fb..88a56d2 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -270,7 +270,7 @@
bool needNativeBridge = false;
void* handle = OpenNativeLibrary(env, sdkVersion, pathStr, classLoader,
- libraryPath, isolationPath);
+ false, libraryPath, isolationPath);
if (handle == NULL) {
if (NativeBridgeIsSupported(pathStr)) {
handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
new file mode 100644
index 0000000..53d4c6a
--- /dev/null
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "jni.h"
+#include "GraphicsJNI.h"
+#include "core_jni_helpers.h"
+#include "log/log.h"
+
+#include "Paint.h"
+#include "VectorDrawable.h"
+
+namespace android {
+using namespace uirenderer;
+using namespace uirenderer::VectorDrawable;
+
+static jlong createTree(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* rootGroup = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ VectorDrawable::Tree* tree = new VectorDrawable::Tree(rootGroup);
+ return reinterpret_cast<jlong>(tree);
+}
+
+static void deleteTree(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ delete tree;
+}
+
+static void setTreeViewportSize(JNIEnv*, jobject, jlong treePtr,
+ jfloat viewportWidth, jfloat viewportHeight) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setViewportSize(viewportWidth, viewportHeight);
+}
+
+static jboolean setRootAlpha(JNIEnv*, jobject, jlong treePtr, jfloat alpha) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->setRootAlpha(alpha);
+}
+
+static jfloat getRootAlpha(JNIEnv*, jobject, jlong treePtr) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ return tree->getRootAlpha();
+}
+
+static void setAllowCaching(JNIEnv*, jobject, jlong treePtr, jboolean allowCaching) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ tree->setAllowCaching(allowCaching);
+}
+
+static void draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr,
+ jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) {
+ VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr);
+ Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
+ SkRect rect;
+ GraphicsJNI::jrect_to_rect(env, jrect, &rect);
+ SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+ tree->draw(canvas, colorFilter, rect, needsMirroring, canReuseCache);
+}
+
+static jlong createEmptyFullPath(JNIEnv*, jobject) {
+ VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath();
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createFullPath(JNIEnv*, jobject, jlong srcFullPathPtr) {
+ VectorDrawable::FullPath* srcFullPath =
+ reinterpret_cast<VectorDrawable::FullPath*>(srcFullPathPtr);
+ VectorDrawable::FullPath* newPath = new VectorDrawable::FullPath(*srcFullPath);
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
+ jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
+ jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
+ jint strokeLineCap, jint strokeLineJoin) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
+ trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
+ strokeLineJoin);
+}
+
+static jboolean getFullPathProperties(JNIEnv* env, jobject, jlong fullPathPtr,
+ jbyteArray outProperties, jint length) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ int8_t pathProperties[length];
+ bool success = fullPath->getProperties(pathProperties, length);
+ env->SetByteArrayRegion(outProperties, 0, length, reinterpret_cast<int8_t*>(&pathProperties));
+ return success;
+}
+
+static jboolean getGroupProperties(JNIEnv* env, jobject, jlong groupPtr,
+ jfloatArray outProperties, jint length) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ float groupProperties[length];
+ bool success = group->getProperties(groupProperties, length);
+ env->SetFloatArrayRegion(outProperties, 0, length, reinterpret_cast<float*>(&groupProperties));
+ return success;
+}
+
+static jlong createEmptyClipPath(JNIEnv*, jobject) {
+ VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath();
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createClipPath(JNIEnv*, jobject, jlong srcClipPathPtr) {
+ VectorDrawable::ClipPath* srcClipPath =
+ reinterpret_cast<VectorDrawable::ClipPath*>(srcClipPathPtr);
+ VectorDrawable::ClipPath* newPath = new VectorDrawable::ClipPath(*srcClipPath);
+ return reinterpret_cast<jlong>(newPath);
+}
+
+static jlong createEmptyGroup(JNIEnv*, jobject) {
+ VectorDrawable::Group* newGroup = new VectorDrawable::Group();
+ return reinterpret_cast<jlong>(newGroup);
+}
+
+static jlong createGroup(JNIEnv*, jobject, jlong srcGroupPtr) {
+ VectorDrawable::Group* srcGroup = reinterpret_cast<VectorDrawable::Group*>(srcGroupPtr);
+ VectorDrawable::Group* newGroup = new VectorDrawable::Group(*srcGroup);
+ return reinterpret_cast<jlong>(newGroup);
+}
+
+static void deleteNode(JNIEnv*, jobject, jlong nodePtr) {
+ VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+ delete node;
+}
+
+static void setNodeName(JNIEnv* env, jobject, jlong nodePtr, jstring nameStr) {
+ VectorDrawable::Node* node = reinterpret_cast<VectorDrawable::Node*>(nodePtr);
+ const char* nodeName = env->GetStringUTFChars(nameStr, NULL);
+ node->setName(nodeName);
+ env->ReleaseStringUTFChars(nameStr, nodeName);
+}
+
+static void updateGroupProperties(JNIEnv*, jobject, jlong groupPtr, jfloat rotate, jfloat pivotX,
+ jfloat pivotY, jfloat scaleX, jfloat scaleY, jfloat translateX, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->updateLocalMatrix(rotate, pivotX, pivotY, scaleX, scaleY, translateX, translateY);
+}
+
+static void addChild(JNIEnv*, jobject, jlong groupPtr, jlong childPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ VectorDrawable::Node* child = reinterpret_cast<VectorDrawable::Node*>(childPtr);
+ group->addChild(child);
+}
+
+static void setPathString(JNIEnv* env, jobject, jlong pathPtr, jstring inputStr,
+ jint stringLength) {
+ VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
+ const char* pathString = env->GetStringUTFChars(inputStr, NULL);
+ path->setPath(pathString, stringLength);
+ env->ReleaseStringUTFChars(inputStr, pathString);
+}
+
+static jfloat getRotation(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getRotation();
+}
+
+static void setRotation(JNIEnv*, jobject, jlong groupPtr, jfloat rotation) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setRotation(rotation);
+}
+
+static jfloat getPivotX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getPivotX();
+}
+
+static void setPivotX(JNIEnv*, jobject, jlong groupPtr, jfloat pivotX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setPivotX(pivotX);
+}
+
+static jfloat getPivotY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getPivotY();
+}
+
+static void setPivotY(JNIEnv*, jobject, jlong groupPtr, jfloat pivotY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setPivotY(pivotY);
+}
+
+static jfloat getScaleX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getScaleX();
+}
+
+static void setScaleX(JNIEnv*, jobject, jlong groupPtr, jfloat scaleX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setScaleX(scaleX);
+}
+
+static jfloat getScaleY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getScaleY();
+}
+
+static void setScaleY(JNIEnv*, jobject, jlong groupPtr, jfloat scaleY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setScaleY(scaleY);
+}
+
+static jfloat getTranslateX(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getTranslateX();
+}
+
+static void setTranslateX(JNIEnv*, jobject, jlong groupPtr, jfloat translateX) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setTranslateX(translateX);
+}
+
+static jfloat getTranslateY(JNIEnv*, jobject, jlong groupPtr) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ return group->getTranslateY();
+}
+
+static void setTranslateY(JNIEnv*, jobject, jlong groupPtr, jfloat translateY) {
+ VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(groupPtr);
+ group->setTranslateY(translateY);
+}
+
+static void setPathData(JNIEnv*, jobject, jlong pathPtr, jlong pathDataPtr) {
+ VectorDrawable::Path* path = reinterpret_cast<VectorDrawable::Path*>(pathPtr);
+ PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr);
+ path->setPathData(*pathData);
+}
+
+static jfloat getStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeWidth();
+}
+
+static void setStrokeWidth(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeWidth) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeWidth(strokeWidth);
+}
+
+static jint getStrokeColor(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeColor();
+}
+
+static void setStrokeColor(JNIEnv*, jobject, jlong fullPathPtr, jint strokeColor) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeColor(strokeColor);
+}
+
+static jfloat getStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getStrokeAlpha();
+}
+
+static void setStrokeAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat strokeAlpha) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setStrokeAlpha(strokeAlpha);
+}
+
+static jint getFillColor(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getFillColor();
+}
+
+static void setFillColor(JNIEnv*, jobject, jlong fullPathPtr, jint fillColor) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setFillColor(fillColor);
+}
+
+static jfloat getFillAlpha(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getFillAlpha();
+}
+
+static void setFillAlpha(JNIEnv*, jobject, jlong fullPathPtr, jfloat fillAlpha) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setFillAlpha(fillAlpha);
+}
+
+static jfloat getTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathStart();
+}
+
+static void setTrimPathStart(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathStart) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathStart(trimPathStart);
+}
+
+static jfloat getTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathEnd();
+}
+
+static void setTrimPathEnd(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathEnd) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathEnd(trimPathEnd);
+}
+
+static jfloat getTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ return fullPath->getTrimPathOffset();
+}
+
+static void setTrimPathOffset(JNIEnv*, jobject, jlong fullPathPtr, jfloat trimPathOffset) {
+ VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
+ fullPath->setTrimPathOffset(trimPathOffset);
+}
+
+static const JNINativeMethod gMethods[] = {
+ {"nCreateRenderer", "!(J)J", (void*)createTree},
+ {"nDestroyRenderer", "!(J)V", (void*)deleteTree},
+ {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
+ {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
+ {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
+ {"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
+
+ {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
+ {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
+ {"nCreateFullPath", "!(J)J", (void*)createFullPath},
+ {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
+ {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
+
+ {"nCreateClipPath", "!()J", (void*)createEmptyClipPath},
+ {"nCreateClipPath", "!(J)J", (void*)createClipPath},
+ {"nCreateGroup", "!()J", (void*)createEmptyGroup},
+ {"nCreateGroup", "!(J)J", (void*)createGroup},
+ {"nDestroy", "!(J)V", (void*)deleteNode},
+ {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
+ {"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
+
+ {"nAddChild", "!(JJ)V", (void*)addChild},
+ {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
+
+ {"nGetRotation", "!(J)F", (void*)getRotation},
+ {"nSetRotation", "!(JF)V", (void*)setRotation},
+ {"nGetPivotX", "!(J)F", (void*)getPivotX},
+ {"nSetPivotX", "!(JF)V", (void*)setPivotX},
+ {"nGetPivotY", "!(J)F", (void*)getPivotY},
+ {"nSetPivotY", "!(JF)V", (void*)setPivotY},
+ {"nGetScaleX", "!(J)F", (void*)getScaleX},
+ {"nSetScaleX", "!(JF)V", (void*)setScaleX},
+ {"nGetScaleY", "!(J)F", (void*)getScaleY},
+ {"nSetScaleY", "!(JF)V", (void*)setScaleY},
+ {"nGetTranslateX", "!(J)F", (void*)getTranslateX},
+ {"nSetTranslateX", "!(JF)V", (void*)setTranslateX},
+ {"nGetTranslateY", "!(J)F", (void*)getTranslateY},
+ {"nSetTranslateY", "!(JF)V", (void*)setTranslateY},
+
+ {"nSetPathData", "!(JJ)V", (void*)setPathData},
+ {"nGetStrokeWidth", "!(J)F", (void*)getStrokeWidth},
+ {"nSetStrokeWidth", "!(JF)V", (void*)setStrokeWidth},
+ {"nGetStrokeColor", "!(J)I", (void*)getStrokeColor},
+ {"nSetStrokeColor", "!(JI)V", (void*)setStrokeColor},
+ {"nGetStrokeAlpha", "!(J)F", (void*)getStrokeAlpha},
+ {"nSetStrokeAlpha", "!(JF)V", (void*)setStrokeAlpha},
+ {"nGetFillColor", "!(J)I", (void*)getFillColor},
+ {"nSetFillColor", "!(JI)V", (void*)setFillColor},
+ {"nGetFillAlpha", "!(J)F", (void*)getFillAlpha},
+ {"nSetFillAlpha", "!(JF)V", (void*)setFillAlpha},
+ {"nGetTrimPathStart", "!(J)F", (void*)getTrimPathStart},
+ {"nSetTrimPathStart", "!(JF)V", (void*)setTrimPathStart},
+ {"nGetTrimPathEnd", "!(J)F", (void*)getTrimPathEnd},
+ {"nSetTrimPathEnd", "!(JF)V", (void*)setTrimPathEnd},
+ {"nGetTrimPathOffset", "!(J)F", (void*)getTrimPathOffset},
+ {"nSetTrimPathOffset", "!(JF)V", (void*)setTrimPathOffset},
+};
+
+int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/graphics/drawable/VectorDrawable", gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 7860b74..3746972 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1049,6 +1049,13 @@
pJniStorage->mDeviceCallback.clear();
}
+// FIXME
+#if 0
+static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) {
+ return FCC_8;
+}
+#endif
+
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
@@ -1106,6 +1113,7 @@
{"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
{"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
{"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
+ // FIXME {"native_get_FCC_8", "()I", (void *)android_media_AudioTrack_get_FCC_8},
};
diff --git a/core/jni/android_opengl_GLES32.cpp b/core/jni/android_opengl_GLES32.cpp
new file mode 100644
index 0000000..f9a1a8e
--- /dev/null
+++ b/core/jni/android_opengl_GLES32.cpp
@@ -0,0 +1,1999 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This source file is automatically generated
+
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#include <stdint.h>
+#include <GLES3/gl32.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <utils/misc.h>
+#include <assert.h>
+
+static int initialized = 0;
+
+static jclass nioAccessClass;
+static jclass bufferClass;
+static jmethodID getBasePointerID;
+static jmethodID getBaseArrayID;
+static jmethodID getBaseArrayOffsetID;
+static jfieldID positionID;
+static jfieldID limitID;
+static jfieldID elementSizeShiftID;
+
+
+/* special calls implemented in Android's GLES wrapper used to more
+ * efficiently bound-check passed arrays */
+extern "C" {
+#ifdef GL_VERSION_ES_CM_1_1
+GL_API void GL_APIENTRY glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
+ const GLvoid *ptr, GLsizei count);
+GL_API void GL_APIENTRY glNormalPointerBounds(GLenum type, GLsizei stride,
+ const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glTexCoordPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glVertexPointerBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glPointSizePointerOESBounds(GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glMatrixIndexPointerOESBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+GL_API void GL_APIENTRY glWeightPointerOESBounds(GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count);
+#endif
+#ifdef GL_ES_VERSION_2_0
+static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
+ GLboolean normalized, GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glVertexAttribPointer(indx, size, type, normalized, stride, pointer);
+}
+#endif
+#ifdef GL_ES_VERSION_3_0
+static void glVertexAttribIPointerBounds(GLuint indx, GLint size, GLenum type,
+ GLsizei stride, const GLvoid *pointer, GLsizei count) {
+ glVertexAttribIPointer(indx, size, type, stride, pointer);
+}
+#endif
+}
+
+/* Cache method IDs each time the class is loaded. */
+
+static void
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
+{
+ jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
+ nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
+
+ jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
+ bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
+
+ getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
+ "getBasePointer", "(Ljava/nio/Buffer;)J");
+ getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
+ getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
+ "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
+
+ positionID = _env->GetFieldID(bufferClass, "position", "I");
+ limitID = _env->GetFieldID(bufferClass, "limit", "I");
+ elementSizeShiftID =
+ _env->GetFieldID(bufferClass, "_elementSizeShift", "I");
+}
+
+static void *
+getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining, jint *offset)
+{
+ jint position;
+ jint limit;
+ jint elementSizeShift;
+ jlong pointer;
+
+ position = _env->GetIntField(buffer, positionID);
+ limit = _env->GetIntField(buffer, limitID);
+ elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ *remaining = (limit - position) << elementSizeShift;
+ pointer = _env->CallStaticLongMethod(nioAccessClass,
+ getBasePointerID, buffer);
+ if (pointer != 0L) {
+ *array = NULL;
+ return reinterpret_cast<void*>(pointer);
+ }
+
+ *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
+ getBaseArrayID, buffer);
+ *offset = _env->CallStaticIntMethod(nioAccessClass,
+ getBaseArrayOffsetID, buffer);
+
+ return NULL;
+}
+
+class ByteArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jbyteArray array, jboolean* is_copy) {
+ return _env->GetByteArrayElements(array, is_copy);
+ }
+};
+class BooleanArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jbooleanArray array, jboolean* is_copy) {
+ return _env->GetBooleanArrayElements(array, is_copy);
+ }
+};
+class CharArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jcharArray array, jboolean* is_copy) {
+ return _env->GetCharArrayElements(array, is_copy);
+ }
+};
+class ShortArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jshortArray array, jboolean* is_copy) {
+ return _env->GetShortArrayElements(array, is_copy);
+ }
+};
+class IntArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jintArray array, jboolean* is_copy) {
+ return _env->GetIntArrayElements(array, is_copy);
+ }
+};
+class LongArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jlongArray array, jboolean* is_copy) {
+ return _env->GetLongArrayElements(array, is_copy);
+ }
+};
+class FloatArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jfloatArray array, jboolean* is_copy) {
+ return _env->GetFloatArrayElements(array, is_copy);
+ }
+};
+class DoubleArrayGetter {
+public:
+ static void* Get(JNIEnv* _env, jdoubleArray array, jboolean* is_copy) {
+ return _env->GetDoubleArrayElements(array, is_copy);
+ }
+};
+
+template<typename JTYPEARRAY, typename ARRAYGETTER>
+static void*
+getArrayPointer(JNIEnv *_env, JTYPEARRAY array, jboolean* is_copy) {
+ return ARRAYGETTER::Get(_env, array, is_copy);
+}
+
+class ByteArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jbyteArray array, jbyte* data, jboolean commit) {
+ _env->ReleaseByteArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class BooleanArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jbooleanArray array, jboolean* data, jboolean commit) {
+ _env->ReleaseBooleanArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class CharArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jcharArray array, jchar* data, jboolean commit) {
+ _env->ReleaseCharArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class ShortArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jshortArray array, jshort* data, jboolean commit) {
+ _env->ReleaseShortArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class IntArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jintArray array, jint* data, jboolean commit) {
+ _env->ReleaseIntArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class LongArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jlongArray array, jlong* data, jboolean commit) {
+ _env->ReleaseLongArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class FloatArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jfloatArray array, jfloat* data, jboolean commit) {
+ _env->ReleaseFloatArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+class DoubleArrayReleaser {
+public:
+ static void Release(JNIEnv* _env, jdoubleArray array, jdouble* data, jboolean commit) {
+ _env->ReleaseDoubleArrayElements(array, data, commit ? 0 : JNI_ABORT);
+ }
+};
+
+template<typename JTYPEARRAY, typename NTYPEARRAY, typename ARRAYRELEASER>
+static void
+releaseArrayPointer(JNIEnv *_env, JTYPEARRAY array, NTYPEARRAY data, jboolean commit) {
+ ARRAYRELEASER::Release(_env, array, data, commit);
+}
+
+static void
+releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
+{
+ _env->ReleasePrimitiveArrayCritical(array, data,
+ commit ? 0 : JNI_ABORT);
+}
+
+static void *
+getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
+ char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+ if (buf) {
+ jint position = _env->GetIntField(buffer, positionID);
+ jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
+ buf += position << elementSizeShift;
+ } else {
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
+ }
+ return (void*) buf;
+}
+
+// --------------------------------------------------------------------------
+
+/*
+ * returns the number of values glGet returns for a given pname.
+ *
+ * The code below is written such that pnames requiring only one values
+ * are the default (and are not explicitely tested for). This makes the
+ * checking code much shorter/readable/efficient.
+ *
+ * This means that unknown pnames (e.g.: extensions) will default to 1. If
+ * that unknown pname needs more than 1 value, then the validation check
+ * is incomplete and the app may crash if it passed the wrong number params.
+ */
+static int getNeededCount(GLint pname) {
+ int needed = 1;
+#ifdef GL_ES_VERSION_2_0
+ // GLES 2.x pnames
+ switch (pname) {
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ needed = 2;
+ break;
+
+ case GL_BLEND_COLOR:
+ case GL_COLOR_CLEAR_VALUE:
+ case GL_COLOR_WRITEMASK:
+ case GL_SCISSOR_BOX:
+ case GL_VIEWPORT:
+ needed = 4;
+ break;
+
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+ break;
+
+ case GL_SHADER_BINARY_FORMATS:
+ glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &needed);
+ break;
+ }
+#endif
+
+#ifdef GL_VERSION_ES_CM_1_1
+ // GLES 1.x pnames
+ switch (pname) {
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ case GL_DEPTH_RANGE:
+ case GL_SMOOTH_LINE_WIDTH_RANGE:
+ case GL_SMOOTH_POINT_SIZE_RANGE:
+ needed = 2;
+ break;
+
+ case GL_CURRENT_NORMAL:
+ case GL_POINT_DISTANCE_ATTENUATION:
+ needed = 3;
+ break;
+
+ case GL_COLOR_CLEAR_VALUE:
+ case GL_COLOR_WRITEMASK:
+ case GL_CURRENT_COLOR:
+ case GL_CURRENT_TEXTURE_COORDS:
+ case GL_FOG_COLOR:
+ case GL_LIGHT_MODEL_AMBIENT:
+ case GL_SCISSOR_BOX:
+ case GL_VIEWPORT:
+ needed = 4;
+ break;
+
+ case GL_MODELVIEW_MATRIX:
+ case GL_PROJECTION_MATRIX:
+ case GL_TEXTURE_MATRIX:
+ needed = 16;
+ break;
+
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &needed);
+ break;
+ }
+#endif
+ return needed;
+}
+
+template <typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+ typename ARRAYRELEASER, typename CTYPE, void GET(GLenum, CTYPE*)>
+static void
+get
+ (JNIEnv *_env, jobject _this, jint pname, JTYPEARRAY params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType;
+ const char * _exceptionMessage;
+ CTYPE *params_base = (CTYPE *) 0;
+ jint _remaining;
+ CTYPE *params = (CTYPE *) 0;
+ int _needed = 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ _needed = getNeededCount(pname);
+ // if we didn't find this pname, we just assume the user passed
+ // an array of the right size -- this might happen with extensions
+ // or if we forget an enum here.
+ if (_remaining < _needed) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "length - offset < needed";
+ goto exit;
+ }
+ params_base = (CTYPE *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+ _env, params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ GET(
+ (GLenum)pname,
+ (CTYPE *)params
+ );
+
+exit:
+ if (params_base) {
+ releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+ _env, params_ref, params_base, !_exception);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+
+template <typename CTYPE, typename JTYPEARRAY, typename ARRAYGETTER, typename NTYPEARRAY,
+ typename ARRAYRELEASER, void GET(GLenum, CTYPE*)>
+static void
+getarray
+ (JNIEnv *_env, jobject _this, jint pname, jobject params_buf) {
+ jint _exception = 0;
+ const char * _exceptionType;
+ const char * _exceptionMessage;
+ JTYPEARRAY _array = (JTYPEARRAY) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ CTYPE *params = (CTYPE *) 0;
+ int _needed = 0;
+
+ params = (CTYPE *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ _remaining /= sizeof(CTYPE); // convert from bytes to item count
+ _needed = getNeededCount(pname);
+ // if we didn't find this pname, we just assume the user passed
+ // an array of the right size -- this might happen with extensions
+ // or if we forget an enum here.
+ if (_needed>0 && _remaining < _needed) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < needed";
+ goto exit;
+ }
+ if (params == NULL) {
+ char * _paramsBase = (char *) getArrayPointer<JTYPEARRAY, ARRAYGETTER>(
+ _env, _array, (jboolean *) 0);
+ params = (CTYPE *) (_paramsBase + _bufferOffset);
+ }
+ GET(
+ (GLenum)pname,
+ (CTYPE *)params
+ );
+
+exit:
+ if (_array) {
+ releaseArrayPointer<JTYPEARRAY, NTYPEARRAY, ARRAYRELEASER>(
+ _env, _array, (NTYPEARRAY)params, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+// --------------------------------------------------------------------------
+/* void glBlendBarrier ( void ) */
+static void
+android_glBlendBarrier__
+ (JNIEnv *_env, jobject _this) {
+ glBlendBarrier();
+}
+
+/* void glCopyImageSubData ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth ) */
+static void
+android_glCopyImageSubData__IIIIIIIIIIIIIII
+ (JNIEnv *_env, jobject _this, jint srcName, jint srcTarget, jint srcLevel, jint srcX, jint srcY, jint srcZ, jint dstName, jint dstTarget, jint dstLevel, jint dstX, jint dstY, jint dstZ, jint srcWidth, jint srcHeight, jint srcDepth) {
+ glCopyImageSubData(
+ (GLuint)srcName,
+ (GLenum)srcTarget,
+ (GLint)srcLevel,
+ (GLint)srcX,
+ (GLint)srcY,
+ (GLint)srcZ,
+ (GLuint)dstName,
+ (GLenum)dstTarget,
+ (GLint)dstLevel,
+ (GLint)dstX,
+ (GLint)dstY,
+ (GLint)dstZ,
+ (GLsizei)srcWidth,
+ (GLsizei)srcHeight,
+ (GLsizei)srcDepth
+ );
+}
+
+/* void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) */
+static void
+android_glDebugMessageControl__IIII_3IIZ
+ (JNIEnv *_env, jobject _this, jint source, jint type, jint severity, jint count, jintArray ids_ref, jint offset, jboolean enabled) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *ids_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *ids = (GLuint *) 0;
+
+ if (!ids_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "ids == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(ids_ref) - offset;
+ if (_remaining < count) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "length - offset < count < needed";
+ goto exit;
+ }
+ ids_base = (GLuint *)
+ _env->GetIntArrayElements(ids_ref, (jboolean *)0);
+ ids = ids_base + offset;
+
+ glDebugMessageControl(
+ (GLenum)source,
+ (GLenum)type,
+ (GLenum)severity,
+ (GLsizei)count,
+ (GLuint *)ids,
+ (GLboolean)enabled
+ );
+
+exit:
+ if (ids_base) {
+ _env->ReleaseIntArrayElements(ids_ref, (jint*)ids_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled ) */
+static void
+android_glDebugMessageControl__IIIILjava_nio_IntBuffer_2Z
+ (JNIEnv *_env, jobject _this, jint source, jint type, jint severity, jint count, jobject ids_buf, jboolean enabled) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *ids = (GLuint *) 0;
+
+ ids = (GLuint *)getPointer(_env, ids_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < count) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < count < needed";
+ goto exit;
+ }
+ if (ids == NULL) {
+ char * _idsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ ids = (GLuint *) (_idsBase + _bufferOffset);
+ }
+ glDebugMessageControl(
+ (GLenum)source,
+ (GLenum)type,
+ (GLenum)severity,
+ (GLsizei)count,
+ (GLuint *)ids,
+ (GLboolean)enabled
+ );
+
+exit:
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)ids, JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glDebugMessageInsert ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf ) */
+static void
+android_glDebugMessageInsert__IIIIILjava_lang_String_2
+ (JNIEnv *_env, jobject _this, jint source, jint type, jint id, jint severity, jint length, jstring buf) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ const char* _nativebuf = 0;
+
+ if (!buf) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "buf == null";
+ goto exit;
+ }
+ _nativebuf = _env->GetStringUTFChars(buf, 0);
+
+ glDebugMessageInsert(
+ (GLenum)source,
+ (GLenum)type,
+ (GLuint)id,
+ (GLenum)severity,
+ (GLsizei)length,
+ (GLchar *)_nativebuf
+ );
+
+exit:
+ if (_nativebuf) {
+ _env->ReleaseStringUTFChars(buf, _nativebuf);
+ }
+
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam ) */
+static void
+android_glDebugMessageCallback(JNIEnv *_env, jobject _this, jobject callback) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+}
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jint
+android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI
+ (JNIEnv *_env, jobject _this, jint count, jint bufSize, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset, jintArray lengths_ref, jint lengthsOffset, jbyteArray messageLog_ref, jint messageLogOffset) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static uint
+android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+ (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref, jobject lengths_ref, jobject messageLog_ref) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jobjectArray
+android_glGetDebugMessageLog__I_3II_3II_3II_3II
+ (JNIEnv *_env, jobject _this, jint count, jintArray sources_ref, jint sourcesOffset, jintArray types_ref, jint typesOffset, jintArray ids_ref, jint idsOffset, jintArray severities_ref, jint severitiesOffset) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return 0;
+}
+
+/* GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog ) */
+static jobjectArray
+android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint count, jobject sources_ref, jobject types_ref, jobject ids_ref, jobject severities_ref) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return 0;
+}
+/* void glPushDebugGroup ( GLenum source, GLuint id, GLsizei length, const GLchar *message ) */
+static void
+android_glPushDebugGroup__IIILjava_lang_String_2
+ (JNIEnv *_env, jobject _this, jint source, jint id, jint length, jstring message) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ const char* _nativemessage = 0;
+ jsize _stringlen = 0;
+
+ if (!message) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "message == null";
+ goto exit;
+ }
+ _nativemessage = _env->GetStringUTFChars(message, 0);
+ _stringlen = _env->GetStringUTFLength(message);
+ if (length > _stringlen) {
+ _exception = 1;
+ _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+ _exceptionMessage = "length of message is shorter than length argument";
+ goto exit;
+ }
+
+ glPushDebugGroup(
+ (GLenum)source,
+ (GLuint)id,
+ (GLsizei)length,
+ (GLchar *)_nativemessage
+ );
+
+exit:
+ if (_nativemessage) {
+ _env->ReleaseStringUTFChars(message, _nativemessage);
+ }
+
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glPopDebugGroup ( void ) */
+static void
+android_glPopDebugGroup__
+ (JNIEnv *_env, jobject _this) {
+ glPopDebugGroup();
+}
+
+/* void glObjectLabel ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label ) */
+static void
+android_glObjectLabel__IIILjava_lang_String_2
+ (JNIEnv *_env, jobject _this, jint identifier, jint name, jint length, jstring label) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ const char* _nativelabel = 0;
+ jsize _stringlen = 0;
+
+ if (label) {
+ _nativelabel = _env->GetStringUTFChars(label, 0);
+ _stringlen = _env->GetStringUTFLength(label);
+ if (length > _stringlen) {
+ _exception = 1;
+ _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+ _exceptionMessage = "length of label is shorter than length argument";
+ goto exit;
+ }
+ }
+
+ glObjectLabel(
+ (GLenum)identifier,
+ (GLuint)name,
+ (GLsizei)length,
+ (GLchar *)_nativelabel
+ );
+
+exit:
+ if (_nativelabel) {
+ _env->ReleaseStringUTFChars(label, _nativelabel);
+ }
+
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label ) */
+static jstring
+android_glGetObjectLabel(JNIEnv *_env, jobject _this, jint identifier, jint name) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return NULL;
+}
+
+/* void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label ) */
+static void
+android_glObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr, jstring label) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+}
+
+/* void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label ) */
+static jstring
+android_glGetObjectPtrLabel(JNIEnv *_env, jobject _this, jlong ptr) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return NULL;
+}
+
+/* void glGetPointerv ( GLenum pname, void **params ) */
+static jlong
+android_glGetPointerv(JNIEnv *_env, jobject _this, jint pname) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "not yet implemented");
+ return NULL;
+}
+
+/* void glEnablei ( GLenum target, GLuint index ) */
+static void
+android_glEnablei__II
+ (JNIEnv *_env, jobject _this, jint target, jint index) {
+ glEnablei(
+ (GLenum)target,
+ (GLuint)index
+ );
+}
+
+/* void glDisablei ( GLenum target, GLuint index ) */
+static void
+android_glDisablei__II
+ (JNIEnv *_env, jobject _this, jint target, jint index) {
+ glDisablei(
+ (GLenum)target,
+ (GLuint)index
+ );
+}
+
+/* void glBlendEquationi ( GLuint buf, GLenum mode ) */
+static void
+android_glBlendEquationi__II
+ (JNIEnv *_env, jobject _this, jint buf, jint mode) {
+ glBlendEquationi(
+ (GLuint)buf,
+ (GLenum)mode
+ );
+}
+
+/* void glBlendEquationSeparatei ( GLuint buf, GLenum modeRGB, GLenum modeAlpha ) */
+static void
+android_glBlendEquationSeparatei__III
+ (JNIEnv *_env, jobject _this, jint buf, jint modeRGB, jint modeAlpha) {
+ glBlendEquationSeparatei(
+ (GLuint)buf,
+ (GLenum)modeRGB,
+ (GLenum)modeAlpha
+ );
+}
+
+/* void glBlendFunci ( GLuint buf, GLenum src, GLenum dst ) */
+static void
+android_glBlendFunci__III
+ (JNIEnv *_env, jobject _this, jint buf, jint src, jint dst) {
+ glBlendFunci(
+ (GLuint)buf,
+ (GLenum)src,
+ (GLenum)dst
+ );
+}
+
+/* void glBlendFuncSeparatei ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha ) */
+static void
+android_glBlendFuncSeparatei__IIIII
+ (JNIEnv *_env, jobject _this, jint buf, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
+ glBlendFuncSeparatei(
+ (GLuint)buf,
+ (GLenum)srcRGB,
+ (GLenum)dstRGB,
+ (GLenum)srcAlpha,
+ (GLenum)dstAlpha
+ );
+}
+
+/* void glColorMaski ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a ) */
+static void
+android_glColorMaski__IZZZZ
+ (JNIEnv *_env, jobject _this, jint index, jboolean r, jboolean g, jboolean b, jboolean a) {
+ glColorMaski(
+ (GLuint)index,
+ (GLboolean)r,
+ (GLboolean)g,
+ (GLboolean)b,
+ (GLboolean)a
+ );
+}
+
+/* GLboolean glIsEnabledi ( GLenum target, GLuint index ) */
+static jboolean
+android_glIsEnabledi__II
+ (JNIEnv *_env, jobject _this, jint target, jint index) {
+ GLboolean _returnValue;
+ _returnValue = glIsEnabledi(
+ (GLenum)target,
+ (GLuint)index
+ );
+ return (jboolean)_returnValue;
+}
+
+/* void glDrawElementsBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex ) */
+static void
+android_glDrawElementsBaseVertex__IIILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint basevertex) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ void *indices = (void *) 0;
+
+ indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < count-basevertex) {
+ _exception = 1;
+ _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+ _exceptionMessage = "remaining() < count-basevertex < needed";
+ goto exit;
+ }
+ if (indices == NULL) {
+ char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ indices = (void *) (_indicesBase + _bufferOffset);
+ }
+ glDrawElementsBaseVertex(
+ (GLenum)mode,
+ (GLsizei)count,
+ (GLenum)type,
+ (void *)indices,
+ (GLint)basevertex
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, indices, JNI_FALSE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glDrawRangeElementsBaseVertex ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex ) */
+static void
+android_glDrawRangeElementsBaseVertex__IIIIILjava_nio_Buffer_2I
+ (JNIEnv *_env, jobject _this, jint mode, jint start, jint end, jint count, jint type, jobject indices_buf, jint basevertex) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ void *indices = (void *) 0;
+
+ indices = (void *)getPointer(_env, indices_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < count-basevertex) {
+ _exception = 1;
+ _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+ _exceptionMessage = "remaining() < count-basevertex < needed";
+ goto exit;
+ }
+ if (indices == NULL) {
+ char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ indices = (void *) (_indicesBase + _bufferOffset);
+ }
+ glDrawRangeElementsBaseVertex(
+ (GLenum)mode,
+ (GLuint)start,
+ (GLuint)end,
+ (GLsizei)count,
+ (GLenum)type,
+ (void *)indices,
+ (GLint)basevertex
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, indices, JNI_FALSE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */
+static void
+android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II
+ (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jobject indices_buf, jint instanceCount, jint basevertex) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ void *indices = (void *) 0;
+
+ indices = (void *)getPointer(_env, indices_buf, &_array, &_remaining, &_bufferOffset);
+ if (_remaining < count-basevertex) {
+ _exception = 1;
+ _exceptionType = "java/lang/ArrayIndexOutOfBoundsException";
+ _exceptionMessage = "remaining() < count-basevertex < needed";
+ goto exit;
+ }
+ if (indices == NULL) {
+ char * _indicesBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ indices = (void *) (_indicesBase + _bufferOffset);
+ }
+ glDrawElementsInstancedBaseVertex(
+ (GLenum)mode,
+ (GLsizei)count,
+ (GLenum)type,
+ (void *)indices,
+ (GLsizei)instanceCount,
+ (GLint) basevertex
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, indices, JNI_FALSE);
+ }
+}
+
+/* void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex ) */
+static void
+android_glDrawElementsInstancedBaseVertex__IIIIII
+ (JNIEnv *_env, jobject _this, jint mode, jint count, jint type, jint indicesOffset, jint instanceCount, jint basevertex) {
+ glDrawElementsInstancedBaseVertex(
+ (GLenum)mode,
+ (GLsizei)count,
+ (GLenum)type,
+ (void *)static_cast<uintptr_t>(indicesOffset),
+ (GLsizei)instanceCount,
+ (GLint)basevertex
+ );
+}
+/* void glFramebufferTexture ( GLenum target, GLenum attachment, GLuint texture, GLint level ) */
+static void
+android_glFramebufferTexture__IIII
+ (JNIEnv *_env, jobject _this, jint target, jint attachment, jint texture, jint level) {
+ glFramebufferTexture(
+ (GLenum)target,
+ (GLenum)attachment,
+ (GLuint)texture,
+ (GLint)level
+ );
+}
+
+/* void glPrimitiveBoundingBox ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW ) */
+static void
+android_glPrimitiveBoundingBox__FFFFFFFF
+ (JNIEnv *_env, jobject _this, jfloat minX, jfloat minY, jfloat minZ, jfloat minW, jfloat maxX, jfloat maxY, jfloat maxZ, jfloat maxW) {
+ glPrimitiveBoundingBox(
+ (GLfloat)minX,
+ (GLfloat)minY,
+ (GLfloat)minZ,
+ (GLfloat)minW,
+ (GLfloat)maxX,
+ (GLfloat)maxY,
+ (GLfloat)maxZ,
+ (GLfloat)maxW
+ );
+}
+
+/* GLenum glGetGraphicsResetStatus ( void ) */
+static jint
+android_glGetGraphicsResetStatus__
+ (JNIEnv *_env, jobject _this) {
+ GLenum _returnValue;
+ _returnValue = glGetGraphicsResetStatus();
+ return (jint)_returnValue;
+}
+
+/* void glReadnPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data ) */
+static void
+android_glReadnPixels__IIIIIIILjava_nio_Buffer_2
+ (JNIEnv *_env, jobject _this, jint x, jint y, jint width, jint height, jint format, jint type, jint bufSize, jobject data_buf) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jarray _array = (jarray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ void *data = (void *) 0;
+
+ data = (void *)getPointer(_env, data_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < bufSize < needed";
+ goto exit;
+ }
+ if (data == NULL) {
+ char * _dataBase = (char *)_env->GetPrimitiveArrayCritical(_array, (jboolean *) 0);
+ data = (void *) (_dataBase + _bufferOffset);
+ }
+ glReadnPixels(
+ (GLint)x,
+ (GLint)y,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLenum)format,
+ (GLenum)type,
+ (GLsizei)bufSize,
+ (void *)data
+ );
+
+exit:
+ if (_array) {
+ releasePointer(_env, _array, data, _exception ? JNI_FALSE : JNI_TRUE);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params ) */
+static void
+android_glGetnUniformfv__III_3FI
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jfloatArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLfloat *params_base = (GLfloat *) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "length - offset < bufSize < needed";
+ goto exit;
+ }
+ params_base = (GLfloat *)
+ _env->GetFloatArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetnUniformfv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLfloat *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseFloatArrayElements(params_ref, (jfloat*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params ) */
+static void
+android_glGetnUniformfv__IIILjava_nio_FloatBuffer_2
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jfloatArray _array = (jfloatArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLfloat *params = (GLfloat *) 0;
+
+ params = (GLfloat *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < bufSize < needed";
+ goto exit;
+ }
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetFloatArrayElements(_array, (jboolean *) 0);
+ params = (GLfloat *) (_paramsBase + _bufferOffset);
+ }
+ glGetnUniformfv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLfloat *)params
+ );
+
+exit:
+ if (_array) {
+ _env->ReleaseFloatArrayElements(_array, (jfloat*)params, _exception ? JNI_ABORT : 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetnUniformiv__III_3II
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "length - offset < bufSize < needed";
+ goto exit;
+ }
+ params_base = (GLint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetnUniformiv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params ) */
+static void
+android_glGetnUniformiv__IIILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < bufSize < needed";
+ goto exit;
+ }
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLint *) (_paramsBase + _bufferOffset);
+ }
+ glGetnUniformiv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLint *)params
+ );
+
+exit:
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params ) */
+static void
+android_glGetnUniformuiv__III_3II
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *params_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "length - offset < bufSize < needed";
+ goto exit;
+ }
+ params_base = (GLuint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetnUniformuiv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLuint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params ) */
+static void
+android_glGetnUniformuiv__IIILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint program, jint location, jint bufSize, jobject params_buf) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (_remaining < bufSize) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "remaining() < bufSize < needed";
+ goto exit;
+ }
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLuint *) (_paramsBase + _bufferOffset);
+ }
+ glGetnUniformuiv(
+ (GLuint)program,
+ (GLint)location,
+ (GLsizei)bufSize,
+ (GLuint *)params
+ );
+
+exit:
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, _exception ? JNI_ABORT : 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glMinSampleShading ( GLfloat value ) */
+static void
+android_glMinSampleShading__F
+ (JNIEnv *_env, jobject _this, jfloat value) {
+ glMinSampleShading(
+ (GLfloat)value
+ );
+}
+
+/* void glPatchParameteri ( GLenum pname, GLint value ) */
+static void
+android_glPatchParameteri__II
+ (JNIEnv *_env, jobject _this, jint pname, jint value) {
+ glPatchParameteri(
+ (GLenum)pname,
+ (GLint)value
+ );
+}
+
+/* void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameterIiv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexParameterIiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params ) */
+static void
+android_glTexParameterIiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLint *) (_paramsBase + _bufferOffset);
+ }
+ glTexParameterIiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
+ }
+}
+
+/* void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) */
+static void
+android_glTexParameterIuiv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *params_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLuint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glTexParameterIuiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params ) */
+static void
+android_glTexParameterIuiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLuint *) (_paramsBase + _bufferOffset);
+ }
+ glTexParameterIuiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, JNI_ABORT);
+ }
+}
+
+/* void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameterIiv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexParameterIiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params ) */
+static void
+android_glGetTexParameterIiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLint *) (_paramsBase + _bufferOffset);
+ }
+ glGetTexParameterIiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+ }
+}
+
+/* void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params ) */
+static void
+android_glGetTexParameterIuiv__II_3II
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *params_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLuint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetTexParameterIuiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params ) */
+static void
+android_glGetTexParameterIuiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLuint *) (_paramsBase + _bufferOffset);
+ }
+ glGetTexParameterIuiv(
+ (GLenum)target,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+ }
+}
+
+/* void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameterIiv__II_3II
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray param_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLint *param_base = (GLint *) 0;
+ jint _remaining;
+ GLint *param = (GLint *) 0;
+
+ if (!param_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "param == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(param_ref) - offset;
+ param_base = (GLint *)
+ _env->GetIntArrayElements(param_ref, (jboolean *)0);
+ param = param_base + offset;
+
+ glSamplerParameterIiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLint *)param
+ );
+
+exit:
+ if (param_base) {
+ _env->ReleaseIntArrayElements(param_ref, (jint*)param_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param ) */
+static void
+android_glSamplerParameterIiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLint *param = (GLint *) 0;
+
+ param = (GLint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (param == NULL) {
+ char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ param = (GLint *) (_paramBase + _bufferOffset);
+ }
+ glSamplerParameterIiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLint *)param
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
+ }
+}
+
+/* void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) */
+static void
+android_glSamplerParameterIuiv__II_3II
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray param_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *param_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *param = (GLuint *) 0;
+
+ if (!param_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "param == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(param_ref) - offset;
+ param_base = (GLuint *)
+ _env->GetIntArrayElements(param_ref, (jboolean *)0);
+ param = param_base + offset;
+
+ glSamplerParameterIuiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLuint *)param
+ );
+
+exit:
+ if (param_base) {
+ _env->ReleaseIntArrayElements(param_ref, (jint*)param_base,
+ JNI_ABORT);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param ) */
+static void
+android_glSamplerParameterIuiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject param_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *param = (GLuint *) 0;
+
+ param = (GLuint *)getPointer(_env, param_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (param == NULL) {
+ char * _paramBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ param = (GLuint *) (_paramBase + _bufferOffset);
+ }
+ glSamplerParameterIuiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLuint *)param
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)param, JNI_ABORT);
+ }
+}
+
+/* void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameterIiv__II_3II
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLint *params_base = (GLint *) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetSamplerParameterIiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params ) */
+static void
+android_glGetSamplerParameterIiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLint *params = (GLint *) 0;
+
+ params = (GLint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLint *) (_paramsBase + _bufferOffset);
+ }
+ glGetSamplerParameterIiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+ }
+}
+
+/* void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params ) */
+static void
+android_glGetSamplerParameterIuiv__II_3II
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jintArray params_ref, jint offset) {
+ jint _exception = 0;
+ const char * _exceptionType = NULL;
+ const char * _exceptionMessage = NULL;
+ GLuint *params_base = (GLuint *) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ if (!params_ref) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "params == null";
+ goto exit;
+ }
+ if (offset < 0) {
+ _exception = 1;
+ _exceptionType = "java/lang/IllegalArgumentException";
+ _exceptionMessage = "offset < 0";
+ goto exit;
+ }
+ _remaining = _env->GetArrayLength(params_ref) - offset;
+ params_base = (GLuint *)
+ _env->GetIntArrayElements(params_ref, (jboolean *)0);
+ params = params_base + offset;
+
+ glGetSamplerParameterIuiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+
+exit:
+ if (params_base) {
+ _env->ReleaseIntArrayElements(params_ref, (jint*)params_base,
+ _exception ? JNI_ABORT: 0);
+ }
+ if (_exception) {
+ jniThrowException(_env, _exceptionType, _exceptionMessage);
+ }
+}
+
+/* void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params ) */
+static void
+android_glGetSamplerParameterIuiv__IILjava_nio_IntBuffer_2
+ (JNIEnv *_env, jobject _this, jint sampler, jint pname, jobject params_buf) {
+ jintArray _array = (jintArray) 0;
+ jint _bufferOffset = (jint) 0;
+ jint _remaining;
+ GLuint *params = (GLuint *) 0;
+
+ params = (GLuint *)getPointer(_env, params_buf, (jarray*)&_array, &_remaining, &_bufferOffset);
+ if (params == NULL) {
+ char * _paramsBase = (char *)_env->GetIntArrayElements(_array, (jboolean *) 0);
+ params = (GLuint *) (_paramsBase + _bufferOffset);
+ }
+ glGetSamplerParameterIuiv(
+ (GLuint)sampler,
+ (GLenum)pname,
+ (GLuint *)params
+ );
+ if (_array) {
+ _env->ReleaseIntArrayElements(_array, (jint*)params, 0);
+ }
+}
+
+/* void glTexBuffer ( GLenum target, GLenum internalformat, GLuint buffer ) */
+static void
+android_glTexBuffer__III
+ (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint buffer) {
+ glTexBuffer(
+ (GLenum)target,
+ (GLenum)internalformat,
+ (GLuint)buffer
+ );
+}
+
+/* void glTexBufferRange ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size ) */
+static void
+android_glTexBufferRange__IIIII
+ (JNIEnv *_env, jobject _this, jint target, jint internalformat, jint buffer, jint offset, jint size) {
+ glTexBufferRange(
+ (GLenum)target,
+ (GLenum)internalformat,
+ (GLuint)buffer,
+ (GLintptr)offset,
+ (GLsizeiptr)size
+ );
+}
+
+/* void glTexStorage3DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations ) */
+static void
+android_glTexStorage3DMultisample__IIIIIIZ
+ (JNIEnv *_env, jobject _this, jint target, jint samples, jint internalformat, jint width, jint height, jint depth, jboolean fixedsamplelocations) {
+ glTexStorage3DMultisample(
+ (GLenum)target,
+ (GLsizei)samples,
+ (GLenum)internalformat,
+ (GLsizei)width,
+ (GLsizei)height,
+ (GLsizei)depth,
+ (GLboolean)fixedsamplelocations
+ );
+}
+
+static const char *classPathName = "android/opengl/GLES32";
+
+static const JNINativeMethod methods[] = {
+{"_nativeClassInit", "()V", (void*)nativeClassInit },
+{"glBlendBarrier", "()V", (void *) android_glBlendBarrier__ },
+{"glCopyImageSubData", "(IIIIIIIIIIIIIII)V", (void *) android_glCopyImageSubData__IIIIIIIIIIIIIII },
+{"glDebugMessageControl", "(IIII[IIZ)V", (void *) android_glDebugMessageControl__IIII_3IIZ },
+{"glDebugMessageControl", "(IIIILjava/nio/IntBuffer;Z)V", (void *) android_glDebugMessageControl__IIIILjava_nio_IntBuffer_2Z },
+{"glDebugMessageInsert", "(IIIIILjava/lang/String;)V", (void *) android_glDebugMessageInsert__IIIIILjava_lang_String_2 },
+{"glDebugMessageCallback", "(Landroid/opengl/GLES32$DebugProc;)V", (void *) android_glDebugMessageCallback },
+{"glGetDebugMessageLog", "(II[II[II[II[II[II[BI)I", (void *) android_glGetDebugMessageLog__II_3II_3II_3II_3II_3II_3BI },
+{"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)I", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
+{"glGetDebugMessageLog", "(I[II[II[II[II)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__I_3II_3II_3II_3II },
+{"glGetDebugMessageLog", "(ILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)[Ljava/lang/String;", (void *) android_glGetDebugMessageLog__ILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
+{"glPushDebugGroup", "(IIILjava/lang/String;)V", (void *) android_glPushDebugGroup__IIILjava_lang_String_2 },
+{"glPopDebugGroup", "()V", (void *) android_glPopDebugGroup__ },
+{"glObjectLabel", "(IIILjava/lang/String;)V", (void *) android_glObjectLabel__IIILjava_lang_String_2 },
+{"glGetObjectLabel", "(II)Ljava/lang/String;", (void *) android_glGetObjectLabel },
+{"glObjectPtrLabel", "(JLjava/lang/String;)V", (void *) android_glObjectPtrLabel },
+{"glGetObjectPtrLabel", "(J)Ljava/lang/String;", (void *) android_glGetObjectPtrLabel },
+{"glGetPointerv", "(I)J", (void *) android_glGetPointerv },
+{"glEnablei", "(II)V", (void *) android_glEnablei__II },
+{"glDisablei", "(II)V", (void *) android_glDisablei__II },
+{"glBlendEquationi", "(II)V", (void *) android_glBlendEquationi__II },
+{"glBlendEquationSeparatei", "(III)V", (void *) android_glBlendEquationSeparatei__III },
+{"glBlendFunci", "(III)V", (void *) android_glBlendFunci__III },
+{"glBlendFuncSeparatei", "(IIIII)V", (void *) android_glBlendFuncSeparatei__IIIII },
+{"glColorMaski", "(IZZZZ)V", (void *) android_glColorMaski__IZZZZ },
+{"glIsEnabledi", "(II)Z", (void *) android_glIsEnabledi__II },
+{"glDrawElementsBaseVertex", "(IIILjava/nio/Buffer;I)V", (void *) android_glDrawElementsBaseVertex__IIILjava_nio_Buffer_2I },
+{"glDrawRangeElementsBaseVertex", "(IIIIILjava/nio/Buffer;I)V", (void *) android_glDrawRangeElementsBaseVertex__IIIIILjava_nio_Buffer_2I },
+{"glDrawElementsInstancedBaseVertex", "(IIILjava/nio/Buffer;II)V", (void *) android_glDrawElementsInstancedBaseVertex__IIILjava_nio_Buffer_2II },
+{"glDrawElementsInstancedBaseVertex", "(IIIIII)V", (void *) android_glDrawElementsInstancedBaseVertex__IIIIII },
+{"glFramebufferTexture", "(IIII)V", (void *) android_glFramebufferTexture__IIII },
+{"glPrimitiveBoundingBox", "(FFFFFFFF)V", (void *) android_glPrimitiveBoundingBox__FFFFFFFF },
+{"glGetGraphicsResetStatus", "()I", (void *) android_glGetGraphicsResetStatus__ },
+{"glReadnPixels", "(IIIIIIILjava/nio/Buffer;)V", (void *) android_glReadnPixels__IIIIIIILjava_nio_Buffer_2 },
+{"glGetnUniformfv", "(III[FI)V", (void *) android_glGetnUniformfv__III_3FI },
+{"glGetnUniformfv", "(IIILjava/nio/FloatBuffer;)V", (void *) android_glGetnUniformfv__IIILjava_nio_FloatBuffer_2 },
+{"glGetnUniformiv", "(III[II)V", (void *) android_glGetnUniformiv__III_3II },
+{"glGetnUniformiv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetnUniformiv__IIILjava_nio_IntBuffer_2 },
+{"glGetnUniformuiv", "(III[II)V", (void *) android_glGetnUniformuiv__III_3II },
+{"glGetnUniformuiv", "(IIILjava/nio/IntBuffer;)V", (void *) android_glGetnUniformuiv__IIILjava_nio_IntBuffer_2 },
+{"glMinSampleShading", "(F)V", (void *) android_glMinSampleShading__F },
+{"glPatchParameteri", "(II)V", (void *) android_glPatchParameteri__II },
+{"glTexParameterIiv", "(II[II)V", (void *) android_glTexParameterIiv__II_3II },
+{"glTexParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glTexParameterIuiv", "(II[II)V", (void *) android_glTexParameterIuiv__II_3II },
+{"glTexParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glTexParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterIiv", "(II[II)V", (void *) android_glGetTexParameterIiv__II_3II },
+{"glGetTexParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glGetTexParameterIuiv", "(II[II)V", (void *) android_glGetTexParameterIuiv__II_3II },
+{"glGetTexParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetTexParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glSamplerParameterIiv", "(II[II)V", (void *) android_glSamplerParameterIiv__II_3II },
+{"glSamplerParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glSamplerParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glSamplerParameterIuiv", "(II[II)V", (void *) android_glSamplerParameterIuiv__II_3II },
+{"glSamplerParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glSamplerParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glGetSamplerParameterIiv", "(II[II)V", (void *) android_glGetSamplerParameterIiv__II_3II },
+{"glGetSamplerParameterIiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetSamplerParameterIiv__IILjava_nio_IntBuffer_2 },
+{"glGetSamplerParameterIuiv", "(II[II)V", (void *) android_glGetSamplerParameterIuiv__II_3II },
+{"glGetSamplerParameterIuiv", "(IILjava/nio/IntBuffer;)V", (void *) android_glGetSamplerParameterIuiv__IILjava_nio_IntBuffer_2 },
+{"glTexBuffer", "(III)V", (void *) android_glTexBuffer__III },
+{"glTexBufferRange", "(IIIII)V", (void *) android_glTexBufferRange__IIIII },
+{"glTexStorage3DMultisample", "(IIIIIIZ)V", (void *) android_glTexStorage3DMultisample__IIIIIIZ },
+};
+
+int register_android_opengl_jni_GLES32(JNIEnv *_env)
+{
+ int err;
+ err = android::AndroidRuntime::registerNativeMethods(_env, classPathName, methods, NELEM(methods));
+ return err;
+}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 90606a35..3473d9d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -578,7 +578,7 @@
return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
}
-static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
{
Vector<String8> locales;
@@ -587,7 +587,7 @@
return NULL;
}
- am->getLocales(&locales);
+ am->getLocales(&locales, includeSystemLocales);
const int N = locales.size();
@@ -608,6 +608,16 @@
return result;
}
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+ return getLocales(env, clazz, false /* don't include system locales */);
+}
+
static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
jobject result = env->NewObject(gConfigurationOffsets.classObject,
gConfigurationOffsets.constructor);
@@ -2154,6 +2164,8 @@
// Resources.
{ "getLocales", "()[Ljava/lang/String;",
(void*) android_content_AssetManager_getLocales },
+ { "getNonSystemLocales", "()[Ljava/lang/String;",
+ (void*) android_content_AssetManager_getNonSystemLocales },
{ "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
(void*) android_content_AssetManager_getSizeConfigurations },
{ "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2d23cda..7719e31 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -18,8 +18,10 @@
#define LOG_NAMESPACE "log.tag."
#define LOG_TAG "Log_println"
+#include <android-base/macros.h>
#include <assert.h>
#include <cutils/properties.h>
+#include <log/logger.h> // For LOGGER_ENTRY_MAX_PAYLOAD.
#include <utils/Log.h>
#include <utils/String8.h>
@@ -109,12 +111,23 @@
}
/*
+ * In class android.util.Log:
+ * private static native int logger_entry_max_payload_native()
+ */
+static jint android_util_Log_logger_entry_max_payload_native(JNIEnv* env ATTRIBUTE_UNUSED,
+ jobject clazz ATTRIBUTE_UNUSED)
+{
+ return static_cast<jint>(LOGGER_ENTRY_MAX_PAYLOAD);
+}
+
+/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
{ "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
+ { "logger_entry_max_payload_native", "()I", (void*) android_util_Log_logger_entry_max_payload_native },
};
int register_android_util_Log(JNIEnv* env)
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 9b41eb3..d2c99fd 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -27,7 +27,13 @@
#include <SkBitmap.h>
#include <SkRegion.h>
+#if HWUI_NEW_OPS
+#include <RecordingCanvas.h>
+typedef android::uirenderer::RecordingCanvas canvas_t;
+#else
#include <DisplayListCanvas.h>
+typedef android::uirenderer::DisplayListCanvas canvas_t;
+#endif
#include <Rect.h>
#include <RenderNode.h>
#include <CanvasProperty.h>
@@ -46,7 +52,7 @@
static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
jlong canvasPtr, jboolean reorderEnable) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
canvas->insertReorderBarrier(reorderEnable);
}
@@ -56,7 +62,7 @@
static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong functorPtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
canvas->callDrawGLFunction(functor);
}
@@ -80,7 +86,7 @@
static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
@@ -93,7 +99,7 @@
static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
@@ -107,25 +113,25 @@
static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
jobject clazz, jlong canvasPtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
return reinterpret_cast<jlong>(canvas->finishRecording());
}
static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
jint width, jint height) {
- return reinterpret_cast<jlong>(new DisplayListCanvas(width, height));
+ return reinterpret_cast<jlong>(new canvas_t(width, height));
}
static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
jlong canvasPtr, jint width, jint height) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
canvas->reset(width, height);
}
static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
canvas->drawRenderNode(renderNode);
}
@@ -136,7 +142,7 @@
static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
jlong canvasPtr, jlong layerPtr) {
- DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+ canvas_t* canvas = reinterpret_cast<canvas_t*>(canvasPtr);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
canvas->drawLayer(layer);
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index f6e68c4..cf68449 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -465,11 +465,17 @@
anw->query(anw, NATIVE_WINDOW_HEIGHT, &value);
return value;
}
+
static jlong nativeGetNextFrameNumber(JNIEnv *env, jclass clazz, jlong nativeObject) {
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
return surface->getNextFrameNumber();
}
+static jint nativeSetScalingMode(JNIEnv *env, jclass clazz, jlong nativeObject, jint scalingMode) {
+ Surface* surface = reinterpret_cast<Surface*>(nativeObject);
+ return surface->setScalingMode(scalingMode);
+}
+
namespace uirenderer {
using namespace android::uirenderer::renderthread;
@@ -546,6 +552,7 @@
{"nativeGetWidth", "(J)I", (void*)nativeGetWidth },
{"nativeGetHeight", "(J)I", (void*)nativeGetHeight },
{"nativeGetNextFrameNumber", "(J)J", (void*)nativeGetNextFrameNumber },
+ {"nativeSetScalingMode", "(JI)I", (void*)nativeSetScalingMode },
// HWUI context
{"nHwuiCreate", "(JJ)J", (void*) hwui::create },
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 17eb876..5aa6a73 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -262,11 +262,11 @@
env->ReleaseStringUTFChars(jname, name);
}
-static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
+static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
- return proxy->initialize(window);
+ proxy->initialize(window);
}
static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
@@ -492,7 +492,7 @@
{ "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
{ "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
{ "nSetName", "(JLjava/lang/String;)V", (void*) android_view_ThreadedRenderer_setName },
- { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
+ { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
{ "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 96d150b..041e693 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -605,10 +605,32 @@
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
- // Grant CAP_WAKE_ALARM to the Bluetooth process.
jlong capabilities = 0;
+
+ // Grant CAP_WAKE_ALARM to the Bluetooth process.
if (uid == AID_BLUETOOTH) {
- capabilities |= (1LL << CAP_WAKE_ALARM);
+ capabilities |= (1LL << CAP_WAKE_ALARM);
+ }
+
+ // Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
+ bool gid_wakelock_found = false;
+ if (gid == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ } else if (gids != NULL) {
+ jsize gids_num = env->GetArrayLength(gids);
+ ScopedIntArrayRO ar(env, gids);
+ if (ar.get() == NULL) {
+ RuntimeAbort(env, __LINE__, "Bad gids array");
+ }
+ for (int i = 0; i < gids_num; i++) {
+ if (ar[i] == AID_WAKELOCK) {
+ gid_wakelock_found = true;
+ break;
+ }
+ }
+ }
+ if (gid_wakelock_found) {
+ capabilities |= (1LL << CAP_BLOCK_SUSPEND);
}
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index de7f6ed..58dfd81 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -107,6 +107,7 @@
<protected-broadcast android:name="android.backup.intent.CLEAR" />
<protected-broadcast android:name="android.backup.intent.INIT" />
+ <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
<protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -370,11 +371,8 @@
<protected-broadcast android:name="wifi_scan_available" />
<protected-broadcast android:name="action.cne.started" />
- <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<protected-broadcast android:name="android.content.jobscheduler.JOB_DEADLINE_EXPIRED" />
<protected-broadcast android:name="android.intent.action.ACTION_UNSOL_RESPONSE_OEM_HOOK_RAW" />
- <protected-broadcast android:name="android.location.HIGH_POWER_REQUEST_CHANGE" />
- <protected-broadcast android:name="android.location.HIGH_POWER_REQUEST_CHANGE" />
<protected-broadcast android:name="android.net.conn.CONNECTIVITY_CHANGE_SUPL" />
<protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
<protected-broadcast android:name="android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED" />
@@ -385,6 +383,12 @@
<protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" />
<protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" />
+ <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" />
+ <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
+ <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+ <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -891,6 +895,11 @@
android:protectionLevel="normal"
android:permissionFlags="hidden"/>
+ <!-- @hide We need to keep this around for backwards compatibility -->
+ <permission android:name="android.permission.FLASHLIGHT"
+ android:protectionLevel="normal"
+ android:permissionFlags="hidden"/>
+
<!-- ====================================================================== -->
<!-- INSTALL PERMISSIONS -->
<!-- ====================================================================== -->
@@ -1196,14 +1205,6 @@
android:description="@string/permdesc_vibrate"
android:protectionLevel="normal" />
- <!-- Allows access to the flashlight.
- <p>Protection level: normal
- -->
- <permission android:name="android.permission.FLASHLIGHT"
- android:label="@string/permlab_flashlight"
- android:description="@string/permdesc_flashlight"
- android:protectionLevel="normal" />
-
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
from dimming.
<p>Protection level: normal
@@ -1904,7 +1905,7 @@
<!-- Allows an application to bind to third party quick settings tiles.
<p>Should only be requested by the System, should be required by
- QSTileService declarations.-->
+ TileService declarations.-->
<permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
android:protectionLevel="signature" />
diff --git a/core/res/res/drawable/ic_corp_badge_off.xml b/core/res/res/drawable/ic_corp_badge_off.xml
new file mode 100644
index 0000000..6799bf7
--- /dev/null
+++ b/core/res/res/drawable/ic_corp_badge_off.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+
+ <path
+ android:fillColor="#607D8B"
+ android:pathData="M10,0 C15.5228,0,20,4.47715,20,10 C20,15.5228,15.5228,20,10,20
+C4.47715,20,0,15.5228,0,10 C0,4.47715,4.47715,0,10,0 Z" />
+ <path
+ android:pathData="M1.91667,1.91667 L18.0833,1.91667 L18.0833,18.0833 L1.91667,18.0833
+L1.91667,1.91667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M11.9167,11.9167 L11.4167,11.9167 L11.4167,12.8333 L8.5,12.8333 L8.5,11.9167
+L4.16667,11.9167 L4.16667,14.3333 C4.16667,14.8333,4.58333,15.25,5.08333,15.25
+L14.75,15.25 C14.9167,15.25,15,15.25,15.1667,15.1667 L11.9167,11.9167 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M15.8333,13.75 L15.8333,11.9167 L14,11.9167
+C14.6667,12.6667,15.3333,13.3333,15.8333,13.75 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M6.16667,6.16667 L4.66667,6.16667 C4.16667,6.16667,3.75,6.58333,3.75,7.08333
+L3.75,10 C3.75,10.5,4.16667,10.9167,4.66667,10.9167 L8.5,10.9167 L8.5,10 L10,10
+L6.16667,6.16667 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M8.08333,6 L8.08333,5.16667 L11.9167,5.16667 L11.9167,6.08333 L8.16667,6.08333
+C9.66667,7.58333,11.4167,9.33333,12.9167,10.8333 L15.25,10.8333
+C15.75,10.8333,16.1667,10.4167,16.1667,9.91667 L16.1667,7.08333
+C16.1667,6.58333,15.75,6.16667,15.25,6.16667 L12.8333,6.16667 L12.8333,5.25
+L11.9167,4.33333 L8.08333,4.33333 L7.16667,5.16667
+C7.41667,5.41667,7.75,5.75,8.08333,6 Z" />
+ <path
+ android:fillColor="#ffffff"
+ android:pathData="M15.6824,15.676 L14.6807,16.6777 L3.24921,5.24624 L4.25093,4.24452
+L15.6824,15.676 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/core/res/res/drawable/work_widget_mask_view_background.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
copy to core/res/res/drawable/work_widget_mask_view_background.xml
index f11b690..17f0dbc 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
+++ b/core/res/res/drawable/work_widget_mask_view_background.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
@@ -13,12 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF0000FF"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
-</vector>
+ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+ <padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp"/>
+ <stroke android:width="1dp" android:color="#CCCCCC" />
+ </shape>
diff --git a/core/res/res/layout/notification_material_reply_text.xml b/core/res/res/layout/notification_material_reply_text.xml
new file mode 100644
index 0000000..bc22eb4
--- /dev/null
+++ b/core/res/res/layout/notification_material_reply_text.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+
+<!-- Note: this layout is included from a view stub; layout attributes will be overridden. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/notification_content_margin_start">
+
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:id="@+id/action_divider"
+ android:layout_marginBottom="15dp"
+ android:background="@drawable/notification_template_divider" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_3"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+ <TextView
+ android:id="@+id/notification_material_reply_text_1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="15dp"
+ android:layout_marginEnd="@dimen/notification_content_margin_end"
+ android:textAppearance="@style/TextAppearance.Material.Notification.Reply"
+ android:singleLine="true" />
+
+</LinearLayout>
diff --git a/core/res/res/layout/notification_template_material_base.xml b/core/res/res/layout/notification_template_material_base.xml
index b69eb24..fdbbbd6 100644
--- a/core/res/res/layout/notification_template_material_base.xml
+++ b/core/res/res/layout/notification_template_material_base.xml
@@ -25,12 +25,12 @@
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_gravity="top"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="@dimen/notification_content_margin_top"
- android:minHeight="@dimen/notification_min_content_height"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1" />
@@ -42,7 +42,7 @@
android:layout_gravity="bottom"
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginBottom="11dp"
- android:layout_marginEnd="@dimen/notification_content_margin_end">
+ android:layout_marginEnd="@dimen/notification_content_margin_end" >
<include layout="@layout/notification_template_progress" />
</FrameLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index eb02e8b..dfd72c0 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -25,7 +25,7 @@
<FrameLayout
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_min_height"
+ android:layout_height="wrap_content"
android:layout_gravity="top"
android:tag="base"
>
@@ -38,7 +38,7 @@
android:layout_marginStart="@dimen/notification_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:layout_marginTop="@dimen/notification_content_margin_top"
- android:minHeight="@dimen/notification_min_content_height"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1" />
@@ -55,6 +55,11 @@
</FrameLayout>
<include layout="@layout/notification_template_right_icon" />
</FrameLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
<include
layout="@layout/notification_material_action_list"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index 0427c8a..c3db7c5 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -33,6 +33,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginStart="@dimen/notification_content_margin_start"
+ android:layout_marginBottom="@dimen/notification_content_margin_bottom"
android:layout_marginEnd="24dp"
android:layout_toStartOf="@id/right_icon"
android:minHeight="@dimen/notification_min_content_height"
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index 58e3d1b..5c07b9b 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -52,6 +52,13 @@
android:layout_marginBottom="16dp"
android:scaleType="centerCrop"
/>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-16dp"
+ android:layout_marginEnd="-16dp"
+ />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 9e010f2..ebaffc3 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -39,10 +39,11 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
- android:paddingBottom="13dp"
+ android:paddingBottom="@dimen/notification_content_margin_bottom"
android:orientation="horizontal"
android:gravity="top"
android:layout_weight="1"
+ android:layout_marginTop="1.5dp"
>
<com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
android:textAppearance="@style/TextAppearance.Material.Notification"
@@ -62,6 +63,13 @@
android:contentDescription="@string/notification_work_profile_content_description"
/>
</LinearLayout>
+ <ViewStub android:layout="@layout/notification_material_reply_text"
+ android:id="@+id/notification_material_reply_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="-16dp"
+ android:layout_marginEnd="-16dp"
+ />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 8c0abc9..14bf899 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -123,13 +123,6 @@
android:visibility="gone"
android:layout_weight="1"
/>
- <FrameLayout
- android:id="@+id/inbox_end_pad"
- android:layout_width="match_parent"
- android:layout_height="13dp"
- android:visibility="gone"
- android:layout_weight="0"
- />
<include layout="@layout/notification_material_action_list" />
</LinearLayout>
<include layout="@layout/notification_template_right_icon" />
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index dc4afb8..f0ced5f 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -29,7 +29,7 @@
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_min_content_height"
+ android:layout_height="wrap_content"
android:background="#00000000"
android:orientation="horizontal"
android:layout_marginStart="@dimen/notification_content_margin_start"
@@ -43,6 +43,7 @@
android:layout_gravity="fill_vertical"
android:layout_weight="1"
android:minHeight="@dimen/notification_min_content_height"
+ android:paddingBottom="@dimen/notification_content_margin_bottom"
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1"/>
diff --git a/core/res/res/layout/notification_template_part_line1.xml b/core/res/res/layout/notification_template_part_line1.xml
index e7ac408..308b30f 100644
--- a/core/res/res/layout/notification_template_part_line1.xml
+++ b/core/res/res/layout/notification_template_part_line1.xml
@@ -20,7 +20,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:layout_marginBottom="1dp"
>
<TextView android:id="@+id/title"
android:textAppearance="@style/TextAppearance.Material.Notification.Title"
diff --git a/core/res/res/layout/notification_template_part_line3.xml b/core/res/res/layout/notification_template_part_line3.xml
index 76337ac..dc47a48 100644
--- a/core/res/res/layout/notification_template_part_line3.xml
+++ b/core/res/res/layout/notification_template_part_line3.xml
@@ -20,17 +20,18 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:gravity="center_vertical"
+ android:gravity="top"
>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.Material.Notification"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:layout_gravity="center"
+ android:layout_gravity="top"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
+ android:layout_marginTop="1.5dp"
/>
<ImageView android:id="@+id/profile_badge_line3"
android:layout_width="@dimen/notification_badge_size"
diff --git a/core/res/res/layout/text_drag_thumbnail.xml b/core/res/res/layout/text_drag_thumbnail.xml
index 63d2c05..b1a58cd 100644
--- a/core/res/res/layout/text_drag_thumbnail.xml
+++ b/core/res/res/layout/text_drag_thumbnail.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2010, The Android Open Source Project
**
diff --git a/core/res/res/layout/work_widget_mask_view.xml b/core/res/res/layout/work_widget_mask_view.xml
new file mode 100644
index 0000000..ce86ddc
--- /dev/null
+++ b/core/res/res/layout/work_widget_mask_view.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#F3374248" >
+
+ <ImageView android:id="@+id/work_widget_app_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"/>
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:layout_marginBottom="4dp"
+ android:layout_marginRight="4dp"
+ android:src="@drawable/ic_corp_badge_off" />
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index cf4f18d..36c167e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Sluit nou"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
<string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"beheer vibrasie"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Laat die program toe om die vibrator te beheer."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"beheer flitslig"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Laat die program toe om die flitslig te beheer."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"skakel foonnommers direk"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Laat die program toe om telefoonnommers sonder jou tussentrede te bel. Dit kan tot onverwagte heffings of oproepe lei. Let daarop dat dit nie die program toelaat om noodnommers te bel nie. Kwaadwillige programme kan jou geld kos deur oproepe sonder jou bevestiging te maak."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot kitsboodskapoproepdiens"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Sny"</string>
<string name="copy" msgid="2681946229533511987">"Kopieer"</string>
<string name="paste" msgid="5629880836805036433">"Plak"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Plak as skoonteks"</string>
<string name="replace" msgid="5781686059063148930">"Vervang..."</string>
<string name="delete" msgid="6098684844021697789">"Vee uit"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopieer URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Kies teks"</string>
+ <string name="undo" msgid="7905788502491742328">"Ontdoen"</string>
+ <string name="redo" msgid="7759464876566803888">"Herdoen"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekskeuse"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Voeg by woordeboek"</string>
<string name="deleteText" msgid="6979668428458199034">"Vee uit"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Verander muurpapier"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kennisgewingluisteraar"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Toestandverskaffer"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Kennisgewingassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN geaktiveer"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is geaktiveer deur <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak om die netwerk te bestuur."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Opgedateer deur jou administrateur"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Deur jou administrateur uitgevee"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeer: Moet nooit hierdie kennisgewings wys nie"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Laag: Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: Wys hierdie kennisgewings sonder klank"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Hoog: Wys aan die bokant van die kennisgewingslys en maak \'n geluid"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Dringend: Verskyn vlugtig op die skerm en maak \'n geluid"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d minute lank (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Een minuut lank (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> gekies</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4a35fb4..ec16add 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"አሁን ቆልፍ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
<string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
<string name="user_owner_label" msgid="2804351898001038951">"የግል"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ነዛሪ ተቆጣጠር"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"የብርሃንብልጭታ ተቆጣጠር"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"የብልጭታ ብርሃኑን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"በቀጥታ ስልክ ቁጥሮች ደውል"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"መተግበሪያው ያላንተ ጣልቃ ገብነት የስልክ ቁጥሮች ላይ እንዲደውል ይፈቅድለታል። ይህ ያልተጠበቁ ክፍያዎችን ወይም ጥሪዎችን ሊያስከትል ይችላል። ይህ መተግበሪያው የድንገተኛ ስልክ ቁጥሮችን እንዲደውል እንደማይፈቅድለት ልብ በል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ ጥሪዎችን በማድረግ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"የአይኤምኤስ ጥሪ አገልግሎትን ይደርሳል"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ቁረጥ"</string>
<string name="copy" msgid="2681946229533511987">"ግላባጭ"</string>
<string name="paste" msgid="5629880836805036433">"ለጥፍ"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"እንደ ስነጣ አልባ ጽሁፍ ለጥፍ"</string>
<string name="replace" msgid="5781686059063148930">"ተካ..."</string>
<string name="delete" msgid="6098684844021697789">"ሰርዝ"</string>
<string name="copyUrl" msgid="2538211579596067402">"የURL ቅጂ"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ፅሁፍ ምረጥ"</string>
+ <string name="undo" msgid="7905788502491742328">"ቀልብስ"</string>
+ <string name="redo" msgid="7759464876566803888">"ድገም"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"የፅሁፍ ምርጫ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ወደ መዝገበ ቃላት አክል"</string>
<string name="deleteText" msgid="6979668428458199034">"ሰርዝ"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ልጣፍ ለውጥ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ማሳወቂያ አዳማጭ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"የሁኔታ አቅራቢ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"የማሳወቂያ ረዳት"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ነቅቷል።"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN በ<xliff:g id="APP">%s</xliff:g>ገብሯል"</string>
<string name="vpn_text" msgid="3011306607126450322">"አውታረመረብ ለማደራጀት ንካ።"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"በአስተዳዳሪዎ ተዘምኗል"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"የባትሪ ዕድሜን ለማሻሻል ማገዝ እንዲቻል፣ ኢሜይል፣ መልዕክት አላላክ እና ሌሎች በማመሳሰል ላይ የሚመረኮዙ መተግበሪያዎች እርስዎ ካልከፈቱዋቸው በቀር አይዘምኑም።\n\nየባትሪ ኃይል ቆጣቢ የእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ በራስ-ሰር ይጠፋል።"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"የታገደ፦ እነኝህን ማሳወቂያዎች ፈፅሞ አታሳይ"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"ዝቅተኛ፦ በጸጥታ የማሳወቂያ ዝርዝር የታችኛውን ክፍል አሳይ"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"መደበኛ፦ በጸጥታ እነኝህን ማሳወቂያዎች አሳይ"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ከፍተኛ፦ የማሳወቂያዎችን ዝርዝር የላይኛውን ክፍል አሳይ እና ድምፅ አሰማ"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"አስቸኳይ፦ ወደ ገጸ ማያው አንሳ እና ድምፅ ቅዳ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
<item quantity="other">ለ%1$d ደቂቃዎች (እስከ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ድረስ)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ተመርጠዋል</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"የተለያዩ"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c18fc4a..12ef759 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -227,6 +227,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"قفل الآن"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
<string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"نظام Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"شخصي"</string>
@@ -357,8 +358,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"التحكم في الاهتزاز"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"للسماح للتطبيق بالتحكم في الهزّاز."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string>
@@ -878,10 +877,13 @@
<string name="cut" msgid="3092569408438626261">"قص"</string>
<string name="copy" msgid="2681946229533511987">"نسخ"</string>
<string name="paste" msgid="5629880836805036433">"لصق"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"اللصق كنص عادي"</string>
<string name="replace" msgid="5781686059063148930">"استبدال..."</string>
<string name="delete" msgid="6098684844021697789">"حذف"</string>
<string name="copyUrl" msgid="2538211579596067402">"نسخ عنوان URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"تحديد نص"</string>
+ <string name="undo" msgid="7905788502491742328">"تراجع"</string>
+ <string name="redo" msgid="7759464876566803888">"إعادة"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"تحديد النص"</string>
<string name="addToDictionary" msgid="4352161534510057874">"إضافة إلى القاموس"</string>
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
@@ -1135,6 +1137,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغيير الخلفية"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"برنامج تلقّي الإشعارات الصوتية"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"موفر الحالة"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"مساعد الإشعار"</string>
<string name="vpn_title" msgid="19615213552042827">"تم تنشيط الشبكة الظاهرية الخاصة (VPN)"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"تم تنشيط VPN بواسطة <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"المس لإدارة الشبكة."</string>
@@ -1476,12 +1479,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"تم التحديث بواسطة المشرف"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"تم حذف الحزمة عن طريق المشرف"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"للمساعدة في تحسين عمر البطارية، يساعد موفر البطارية في تقليل أداء الجهاز ويفرض قيدًا على الاهتزاز وخدمات الموقع ومعظم بيانات الخلفية. قد لا يتم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم تفتحها.\n\nيتم إيقاف موفر البطارية تلقائيًا أثناء شحن الجهاز."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"الأهمية"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"محظور: عدم عرض هذه الإشعارات مطلقًا"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"منخفض الأهمية: عرض بأسفل قائمة الإشعارات وبدون تنبيه صوتي"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"عادي: عرض هذه الإشعارات بدون تنبيه صوتي"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"عالي الأهمية: عرض بأعلى قائمة الإشعارات مع إصدار تنبيه صوتي"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"عاجل: الظهور سريعًا على الشاشة مع إصدار تنبيه صوتي"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="zero">لمدة أقل من دقيقة (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="two">لمدة دقيقتين (%1$d) (حتى <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 5de0b59..7f0e6d7 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"İndi kilidləyin"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Məzmun gizlidir"</string>
<string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Şəxsi"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tətbiqə kamera ilə şəkil və video çəkməyə imkan yaradır. Bu icazə tətbiqə sizin təsdiqiniz olmadan kameradan istifadə icazəsi verir."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"vibrasiyaya nəzarət edir"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Flash işığını idarə edir"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tətbiqə siqnal işığı na nəzarət etməyə imkan verir."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon nömrələrinə birbaşa zəng edir"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tətbiqə Sizin müdaxiləniz olmadan telefon zəngləri etməyə imkan verir. Zərərli tətbiqlər Sizdən xəbərsiz şəkildə müxtəlif zənglər edərək, Sizə maddi ziyan vura bilər. Qeyd: Bu, tətbiqlərə təcili nömrələrə zəng etməyə icazə vermir."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS zəng xidmətinə giriş"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Kəs"</string>
<string name="copy" msgid="2681946229533511987">"Kopyala"</string>
<string name="paste" msgid="5629880836805036433">"Yerləşdir"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Adi mətn kimi köçürün"</string>
<string name="replace" msgid="5781686059063148930">"Əvəz et..."</string>
<string name="delete" msgid="6098684844021697789">"Sil"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL kopyala"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Mətn seçin"</string>
+ <string name="undo" msgid="7905788502491742328">"Ləğv edin"</string>
+ <string name="redo" msgid="7759464876566803888">"Yenidən edin"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Mətn seçimi"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Lüğətə əlavə et"</string>
<string name="deleteText" msgid="6979668428458199034">"Sil"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Divar kağızını dəyişin"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildiriş dinləyən"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Şərait provayderi"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildiriş köməkçisi"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktivləşdirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tərəfindən aktivləşdirilib"</string>
<string name="vpn_text" msgid="3011306607126450322">"Şəbəkəni idarə etmək üçün toxunun."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Sizin administrator tərəfindən yeniləndi"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratorunuz tərəfindən silinib"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Batareyanın istismar müddətini təkmilləşdirmək üçün batareya qənaəti cihazınızın məhsuldarlığını azaldır və titrətmə, məkan xidmətləri və ən son fon məlumatlarını məhdudlaşdırır. Sinxronlaşmaya arxayın olan e-poçt, mesajlaşma və digər proqramlar siz onları açmayana kimi yenilənməyə bilər.\n\nCihazınız doldurulan zaman batareya qənaəti avtomatik olaraq sönür."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Əhəmiyyət"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blok edildi: Bu bildirişləri heç vaxt göstərməyin"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Alçaq: Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildişləri səssiz göstərin"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Yüksək: Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Təcili: Ekranda nəzər salın və səsli edin"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other"> %1$d dəqiqəlik (saat <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> radəsinə qədər)</item>
<item quantity="one">Bir dəqiqəlik (saat <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> radəsinə qədər)</item>
diff --git a/core/res/res/values-b+sr+Latn-watch/strings.xml b/core/res/res/values-b+sr+Latn-watch/strings.xml
new file mode 100644
index 0000000..7b372ed
--- /dev/null
+++ b/core/res/res/values-b+sr+Latn-watch/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+ <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikacija <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
+</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..ac5ce66
--- /dev/null
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,1531 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+ <string name="byteShort" msgid="8340973892742019101">"B"</string>
+ <string name="kilobyteShort" msgid="5973789783504771878">"kB"</string>
+ <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
+ <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
+ <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
+ <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
+ <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
+ <string name="durationDays" msgid="6652371460511178259">"<xliff:g id="DAYS">%1$d</xliff:g> dana"</string>
+ <string name="durationDayHours" msgid="2713107458736744435">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> s"</string>
+ <string name="durationDayHour" msgid="7293789639090958917">"<xliff:g id="DAYS">%1$d</xliff:g> dan <xliff:g id="HOURS">%2$d</xliff:g> s"</string>
+ <string name="durationHours" msgid="4266858287167358988">"<xliff:g id="HOURS">%1$d</xliff:g> s"</string>
+ <string name="durationHourMinutes" msgid="9029176248692041549">"<xliff:g id="HOURS">%1$d</xliff:g> s <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationHourMinute" msgid="2741677355177402539">"<xliff:g id="HOURS">%1$d</xliff:g> s <xliff:g id="MINUTES">%2$d</xliff:g> min"</string>
+ <string name="durationMinutes" msgid="3134226679883579347">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+ <string name="durationMinute" msgid="7155301744174623818">"<xliff:g id="MINUTES">%1$d</xliff:g> min"</string>
+ <string name="durationMinuteSeconds" msgid="1424656185379003751">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
+ <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sek"</string>
+ <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
+ <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> sek"</string>
+ <string name="untitled" msgid="4638956954852782576">"<Bez naslova>"</string>
+ <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nema broja telefona)"</string>
+ <string name="unknownName" msgid="6867811765370350269">"Nepoznato"</string>
+ <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Glasovna pošta"</string>
+ <string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
+ <string name="mmiError" msgid="5154499457739052907">"Problemi sa vezom ili nevažeći MMI kôd."</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"Rad je ograničen samo na brojeve fiksnog biranja."</string>
+ <string name="serviceEnabled" msgid="8147278346414714315">"Usluga je omogućena."</string>
+ <string name="serviceEnabledFor" msgid="6856228140453471041">"Usluga je omogućena za:"</string>
+ <string name="serviceDisabled" msgid="1937553226592516411">"Usluga je onemogućena."</string>
+ <string name="serviceRegistered" msgid="6275019082598102493">"Registracija je uspela."</string>
+ <string name="serviceErased" msgid="1288584695297200972">"Brisanje je dovršeno."</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"Neispravna lozinka."</string>
+ <string name="mmiComplete" msgid="8232527495411698359">"MMI kôd je izvršen."</string>
+ <string name="badPin" msgid="9015277645546710014">"Stari PIN koji ste uneli nije tačan."</string>
+ <string name="badPuk" msgid="5487257647081132201">"PUK koji ste uneli nije tačan."</string>
+ <string name="mismatchPin" msgid="609379054496863419">"PIN kodovi koje ste uneli se ne podudaraju."</string>
+ <string name="invalidPin" msgid="3850018445187475377">"Otkucajte PIN koji ima od 4 do 8 brojeva."</string>
+ <string name="invalidPuk" msgid="8761456210898036513">"Unesite PUK koji se sastoji od 8 cifara ili više."</string>
+ <string name="needPuk" msgid="919668385956251611">"SIM kartica je zaključana PUK kodom. Unesite PUK kôd da biste je otključali."</string>
+ <string name="needPuk2" msgid="4526033371987193070">"Unesite PUK2 da biste deblokirali SIM karticu."</string>
+ <string name="enablePin" msgid="209412020907207950">"Nije uspelo. Omogućite zaključavanje SIM/RUIM kartice."</string>
+ <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
+ <item quantity="one">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj pre nego što se SIM kartica zaključa.</item>
+ <item quantity="few">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja pre nego što se SIM kartica zaključa.</item>
+ <item quantity="other">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja pre nego što se SIM kartica zaključa.</item>
+ </plurals>
+ <string name="imei" msgid="2625429890869005782">"IMEI"</string>
+ <string name="meid" msgid="4841221237681254195">"MEID"</string>
+ <string name="ClipMmi" msgid="6952821216480289285">"Dolazni ID pozivaoca"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"Odlazni ID pozivaoca"</string>
+ <string name="ColpMmi" msgid="3065121483740183974">"ID povezane linije"</string>
+ <string name="ColrMmi" msgid="4996540314421889589">"Ograničenje ID-a povezane linije"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Preusmeravanje poziva"</string>
+ <string name="CwMmi" msgid="9129678056795016867">"Poziv na čekanju"</string>
+ <string name="BaMmi" msgid="455193067926770581">"Ograničavanje poziva"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"Promena lozinke"</string>
+ <string name="PinMmi" msgid="3113117780361190304">"Promena PIN koda"</string>
+ <string name="CnipMmi" msgid="3110534680557857162">"Pozivanje postojećeg broja"</string>
+ <string name="CnirMmi" msgid="3062102121430548731">"Pozivanje broja je ograničeno"</string>
+ <string name="ThreeWCMmi" msgid="9051047170321190368">"Trosmerno pozivanje"</string>
+ <string name="RuacMmi" msgid="7827887459138308886">"Odbijanje nepoželjnih poziva"</string>
+ <string name="CndMmi" msgid="3116446237081575808">"Isporuka broja za pozivanje"</string>
+ <string name="DndMmi" msgid="1265478932418334331">"Ne uznemiravaj"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID pozivaoca je podrazumevano ograničen. Sledeći poziv: ograničen."</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID pozivaoca je podrazumevano ograničen. Sledeći poziv: Nije ograničen."</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: ograničen."</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID pozivaoca podrazumevano nije ograničen. Sledeći poziv: Nije ograničen."</string>
+ <string name="serviceNotProvisioned" msgid="8614830180508686666">"Usluga nije dobavljena."</string>
+ <string name="CLIRPermanent" msgid="3377371145926835671">"Ne možete da promenite podešavanje ID-a korisnika."</string>
+ <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Ograničeni pristup je promenjen"</string>
+ <string name="RestrictedOnData" msgid="8653794784690065540">"Usluga za podatke je blokirana."</string>
+ <string name="RestrictedOnEmergency" msgid="6581163779072833665">"Usluga za hitne slučajeve je blokirana."</string>
+ <string name="RestrictedOnNormal" msgid="4953867011389750673">"Glasovna usluga je blokirana."</string>
+ <string name="RestrictedOnAllVoice" msgid="3396963652108151260">"Sve glasovne usluge su blokirane."</string>
+ <string name="RestrictedOnSms" msgid="8314352327461638897">"SMS usluga je blokirana."</string>
+ <string name="RestrictedOnVoiceData" msgid="996636487106171320">"Glasovna usluga/usluga prenosa podataka su blokirane."</string>
+ <string name="RestrictedOnVoiceSms" msgid="1888588152792023873">"Glasovna usluga i SMS usluga su blokirane."</string>
+ <string name="RestrictedOnAll" msgid="5643028264466092821">"Sve glasovne i SMS usluge, kao i usluge prenosa podataka su blokirane."</string>
+ <string name="peerTtyModeFull" msgid="6165351790010341421">"Korisnik zahteva POTPUN režim TTY"</string>
+ <string name="peerTtyModeHco" msgid="5728602160669216784">"Korisnik zahteva PRENOS ZVUKA za režim TTY"</string>
+ <string name="peerTtyModeVco" msgid="1742404978686538049">"Korisnik zahteva PRENOS GLASA za režim TTY"</string>
+ <string name="peerTtyModeOff" msgid="3280819717850602205">"Korisnik zahteva ISKLJUČEN režim TTY"</string>
+ <string name="serviceClassVoice" msgid="1258393812335258019">"Voice"</string>
+ <string name="serviceClassData" msgid="872456782077937893">"Podaci"</string>
+ <string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
+ <string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
+ <string name="serviceClassDataAsync" msgid="4523454783498551468">"Asinhroni podaci"</string>
+ <string name="serviceClassDataSync" msgid="7530000519646054776">"Sinhronizovano"</string>
+ <string name="serviceClassPacket" msgid="6991006557993423453">"Paket"</string>
+ <string name="serviceClassPAD" msgid="3235259085648271037">"PODLOGA"</string>
+ <string name="roamingText0" msgid="7170335472198694945">"Indikator rominga je uključen"</string>
+ <string name="roamingText1" msgid="5314861519752538922">"Indikator rominga je isključen"</string>
+ <string name="roamingText2" msgid="8969929049081268115">"Treperenje indikatora rominga"</string>
+ <string name="roamingText3" msgid="5148255027043943317">"Izvan komšiluka"</string>
+ <string name="roamingText4" msgid="8808456682550796530">"Izvan zgrade"</string>
+ <string name="roamingText5" msgid="7604063252850354350">"Roming – željeni sistem"</string>
+ <string name="roamingText6" msgid="2059440825782871513">"Roming – dostupni sistem"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"Roming – partner"</string>
+ <string name="roamingText8" msgid="5989569778604089291">"Roming – premijum partner"</string>
+ <string name="roamingText9" msgid="7969296811355152491">"Roming – potpuno funkcionisanje usluge"</string>
+ <string name="roamingText10" msgid="3992906999815316417">"Roming – delimično funkcionisanje usluge"</string>
+ <string name="roamingText11" msgid="4154476854426920970">"Baner rominga je uključen"</string>
+ <string name="roamingText12" msgid="1189071119992726320">"Baner rominga je isključen"</string>
+ <string name="roamingTextSearching" msgid="8360141885972279963">"Pretraživanje usluge"</string>
+ <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Pozivanje preko Wi-Fi-ja"</string>
+ <string-array name="wfcOperatorErrorAlertMessages">
+ </string-array>
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ </string-array>
+ <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+ <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
+ <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
+ <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
+ <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Prednost ima mobilna mreža"</string>
+ <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Samo Wi-Fi"</string>
+ <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije prosleđeno"</string>
+ <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
+ <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> nakon <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunde(i)"</string>
+ <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije prosleđeno"</string>
+ <string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije prosleđeno"</string>
+ <string name="fcComplete" msgid="3118848230966886575">"Kôd funkcije je izvršen."</string>
+ <string name="fcError" msgid="3327560126588500777">"Problemi sa vezom ili nevažeći kôd funkcije."</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"Potvrdi"</string>
+ <string name="httpError" msgid="7956392511146698522">"Došlo je do greške na mreži."</string>
+ <string name="httpErrorLookup" msgid="4711687456111963163">"Nije moguće pronaći URL adresu"</string>
+ <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"Šema potvrda autentičnosti sajta nije podržana."</string>
+ <string name="httpErrorAuth" msgid="1435065629438044534">"Nije moguće potvrditi autentičnost."</string>
+ <string name="httpErrorProxyAuth" msgid="1788207010559081331">"Potvrda identiteta preko proksi servera nije uspela."</string>
+ <string name="httpErrorConnect" msgid="8714273236364640549">"Nije moguće povezati se sa serverom."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Pokušajte ponovo kasnije."</string>
+ <string name="httpErrorTimeout" msgid="4743403703762883954">"Veza sa serverom je istekla."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stranica sadrži previše veza za preusmeravanje sa servera."</string>
+ <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol nije podržan."</string>
+ <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Nije moguće uspostaviti bezbednu vezu."</string>
+ <string name="httpErrorBadUrl" msgid="3636929722728881972">"Stranicu nije moguće otvoriti zato što je URL adresa nevažeća."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"Nije moguće pristupiti datoteci."</string>
+ <string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nije moguće pronaći traženu datoteku."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Pokušajte ponovo kasnije."</string>
+ <string name="notification_title" msgid="8967710025036163822">"Greška pri prijavljivanju za <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+ <string name="contentServiceSync" msgid="8353523060269335667">"Sinhronizacija"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
+ <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše <xliff:g id="CONTENT_TYPE">%s</xliff:g> izbrisanih stavki."</string>
+ <string name="low_memory" product="tablet" msgid="6494019234102154896">"Memorija tableta je puna! Izbrišite neke datoteke da biste oslobodili prostor."</string>
+ <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+ <string name="low_memory" product="tv" msgid="516619861191025923">"Skladišni prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+ <string name="low_memory" product="default" msgid="3475999286680000541">"Skladište telefona je puno! Izbrišite neke datoteke kako biste oslobodili prostor."</string>
+ <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadgleda"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
+ <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Od strane administratora profila za posao"</string>
+ <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od strane <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
+ <string name="work_profile_deleted" msgid="5005572078641980632">"Poslovni profil je izbrisan"</string>
+ <string name="work_profile_deleted_description" msgid="6305147513054341102">"Poslovni profil je izbrisan jer nedostaje administratorska aplikacija."</string>
+ <string name="work_profile_deleted_details" msgid="226615743462361248">"Administratorska aplikacija poslovnog profila nedostaje ili je oštećena. Zbog toga su vaš poslovni profil i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
+ <string name="work_profile_deleted_description_dpm_wipe" msgid="6019770344820507579">"Profil za Work više nije dostupan na ovom uređaju."</string>
+ <string name="factory_reset_warning" msgid="5423253125642394387">"Uređaj će biti obrisan"</string>
+ <string name="factory_reset_message" msgid="4905025204141900666">"Administratorskoj aplikaciji nedostaju neke komponente ili je oštećena i ne može da se koristi. Uređaj će sada biti obrisan. Obratite se administratoru za pomoć."</string>
+ <string name="me" msgid="6545696007631404292">"Ja"</string>
+ <string name="power_dialog" product="tablet" msgid="8545351420865202853">"Opcije za tablet"</string>
+ <string name="power_dialog" product="tv" msgid="6153888706430556356">"Opcije za TV"</string>
+ <string name="power_dialog" product="default" msgid="1319919075463988638">"Opcije telefona"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"Nečujni režim"</string>
+ <string name="turn_on_radio" msgid="3912793092339962371">"Uključi bežični signal"</string>
+ <string name="turn_off_radio" msgid="8198784949987062346">"Isključi bežični signal"</string>
+ <string name="screen_lock" msgid="799094655496098153">"Zaključaj ekran"</string>
+ <string name="power_off" msgid="4266614107412865048">"Isključi"</string>
+ <string name="silent_mode_silent" msgid="319298163018473078">"Zvono je isključeno"</string>
+ <string name="silent_mode_vibrate" msgid="7072043388581551395">"Vibracija zvona"</string>
+ <string name="silent_mode_ring" msgid="8592241816194074353">"Zvono je uključeno"</string>
+ <string name="reboot_to_update_title" msgid="6212636802536823850">"Android ažuriranje sistema"</string>
+ <string name="reboot_to_update_prepare" msgid="6305853831955310890">"Ažuriranje se priprema…"</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"Paket ažuriranja se obrađuje..."</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"Ponovo se pokreće..."</string>
+ <string name="reboot_to_reset_title" msgid="4142355915340627490">"Resetovanje na fabrička podešavanja"</string>
+ <string name="reboot_to_reset_message" msgid="2432077491101416345">"Ponovo se pokreće..."</string>
+ <string name="shutdown_progress" msgid="2281079257329981203">"Isključivanje…"</string>
+ <string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"Tablet će se isključiti."</string>
+ <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"TV će se isključiti."</string>
+ <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"Sat će se ugasiti."</string>
+ <string name="shutdown_confirm" product="default" msgid="649792175242821353">"Telefon će se isključiti."</string>
+ <string name="shutdown_confirm_question" msgid="2906544768881136183">"Da li želite da isključite telefon?"</string>
+ <string name="reboot_safemode_title" msgid="7054509914500140361">"Ponovo pokreni sistem u bezbednom režimu"</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"Da li želite da ponovo pokrenete sistem u bezbednom režimu? Ovo će onemogućiti sve instalirane aplikacije nezavisnih proizvođača. One će biti vraćene kada ponovo pokrenete sistem."</string>
+ <string name="recent_tasks_title" msgid="3691764623638127888">"Nedavno"</string>
+ <string name="no_recent_tasks" msgid="8794906658732193473">"Nema nedavnih aplikacija."</string>
+ <string name="global_actions" product="tablet" msgid="408477140088053665">"Opcije za tablet"</string>
+ <string name="global_actions" product="tv" msgid="7240386462508182976">"Opcije za TV"</string>
+ <string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"Zaključaj ekran"</string>
+ <string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Nečujni režim"</string>
+ <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Zvuk je ISKLJUČEN"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Zvuk je UKLJUČEN"</string>
+ <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Režim rada u avionu"</string>
+ <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Režim rada u avionu je UKLJUČEN"</string>
+ <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Režim rada u avionu je ISKLJUČEN"</string>
+ <string name="global_action_settings" msgid="1756531602592545966">"Podešavanja"</string>
+ <string name="global_action_assist" msgid="3892832961594295030">"Pomoć"</string>
+ <string name="global_action_voice_assist" msgid="7751191495200504480">"Glasovna pomoć"</string>
+ <string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj odmah"</string>
+ <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
+ <string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je sakriven"</string>
+ <string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
+ <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
+ <string name="user_owner_label" msgid="2804351898001038951">"Lično"</string>
+ <string name="managed_profile_label" msgid="6260850669674791528">"Posao"</string>
+ <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakti"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"pristupi kontaktima"</string>
+ <string name="permgrouplab_location" msgid="7275582855722310164">"Lokacija"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"pristupi lokaciji ovog uređaja"</string>
+ <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendar"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"pristupi kalendaru"</string>
+ <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
+ <string name="permgroupdesc_sms" msgid="4656988620100940350">"šalje i pregleda SMS poruke"</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"Skladište"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"pristupa slikama, medijima i datotekama na uređaju"</string>
+ <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
+ <string name="permgroupdesc_microphone" msgid="4988812113943554584">"snima audio snimke"</string>
+ <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
+ <string name="permgroupdesc_camera" msgid="3250611594678347720">"snima slike i video snimke"</string>
+ <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
+ <string name="permgroupdesc_phone" msgid="6234224354060641055">"upućuje telefonske pozive i upravlja njima"</string>
+ <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupa podacima senzora o vitalnim funkcijama"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Preuzima sadržaj prozora"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Proverava sadržaj prozora sa kojim ostvarujete interakciju."</string>
+ <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključi Istraživanja dodirom"</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Stavke koje dodirnete će biti izgovorene, a možete da se krećete po ekranu pokretima."</string>
+ <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Uključi poboljšanu pristupačnost veba"</string>
+ <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Mogu da se instaliraju skripte da bi sadržaj aplikacija bio pristupačniji."</string>
+ <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Prati tekst koji unosite"</string>
+ <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
+ <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Upravljaj uvećanjem prikaza"</string>
+ <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
+ <string name="permlab_statusBar" msgid="7417192629601890791">"onemogućavanje ili izmena statusne trake"</string>
+ <string name="permdesc_statusBar" msgid="8434669549504290975">"Dozvoljava aplikaciji da onemogući statusnu traku ili da dodaje i uklanja sistemske ikone."</string>
+ <string name="permlab_statusBarService" msgid="4826835508226139688">"funkcionisanje kao statusna traka"</string>
+ <string name="permdesc_statusBarService" msgid="716113660795976060">"Dozvoljava aplikaciji da funkcioniše kao statusna traka."</string>
+ <string name="permlab_expandStatusBar" msgid="1148198785937489264">"proširenje/skupljanje statusne trake"</string>
+ <string name="permdesc_expandStatusBar" msgid="6917549437129401132">"Dozvoljava aplikaciji da proširuje ili skuplja statusnu traku."</string>
+ <string name="permlab_install_shortcut" msgid="4279070216371564234">"instaliranje prečica"</string>
+ <string name="permdesc_install_shortcut" msgid="8341295916286736996">"Omogućava aplikaciji da dodaje prečice na početni ekran bez intervencije korisnika."</string>
+ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"deinstaliranje prečica"</string>
+ <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Omogućava aplikaciji da uklanja prečice sa početnog ekrana bez intervencije korisnika."</string>
+ <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"preusmeravanje odlaznih poziva"</string>
+ <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Dozvoljava aplikaciji da vidi koji broj se bira pri odlaznom pozivu uz opciju da preusmeri poziv na drugi broj ili ga potpuno prekine."</string>
+ <string name="permlab_receiveSms" msgid="8673471768947895082">"prijem tekstualnih poruka (SMS)"</string>
+ <string name="permdesc_receiveSms" msgid="6424387754228766939">"Dozvoljava aplikaciji da prima i obrađuje SMS poruke. To znači da aplikacija može da nadgleda ili briše poruke koje se šalju uređaju, a da vam ih ne prikaže."</string>
+ <string name="permlab_receiveMms" msgid="1821317344668257098">"prijem tekstualnih poruka (MMS)"</string>
+ <string name="permdesc_receiveMms" msgid="533019437263212260">"Dozvoljava aplikaciji da prima i obrađuje MMS poruke. To znači da aplikacija može da nadgleda ili briše poruke koje se šalju uređaju, a da vam ih ne prikaže."</string>
+ <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"čitanje poruka info servisa"</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Omogućava aplikaciji da čita poruke info servisa koje uređaj prima. Upozorenja info servisa se na nekim lokacijama primaju kao upozorenja na hitne slučajeve. Zlonamerne aplikacije mogu da utiču na učinak ili ometaju funkcionisanje uređaja kada se primi poruka info servisa o hitnom slučaju."</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"čitanje prijavljenih fidova"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Dozvoljava aplikaciji da preuzima detalje o trenutno sinhronizovanim fidovima."</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"šalje i pregleda SMS poruke"</string>
+ <string name="permdesc_sendSms" msgid="7094729298204937667">"Dozvoljava aplikaciji da šalje SMS poruke. Ovo može da dovede do neočekivanih troškova. Zlonamerne aplikacije mogu da šalju poruke bez vaše potvrde, što može da izazove troškove."</string>
+ <string name="permlab_readSms" msgid="8745086572213270480">"čitanje tekstualnih poruka (SMS ili MMS)"</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Dozvoljava aplikaciji da čita SMS poruke uskladištene na tabletu ili SIM kartici. Ovo omogućava aplikaciji da čita sve SMS poruke, bez obzira na sadržaj ili poverljivost."</string>
+ <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Dozvoljava aplikaciji da čita SMS poruke koje čuvate na TV-u ili SIM kartici. To znači da aplikacija može da čita sve SMS poruke, nezavisno od sadržaja ili poverljivosti."</string>
+ <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Dozvoljava aplikaciji da čita SMS poruke uskladištene na telefonu ili SIM kartici. Ovo omogućava aplikaciji da čita sve SMS poruke, bez obzira na sadržaj ili poverljivost."</string>
+ <string name="permlab_receiveWapPush" msgid="5991398711936590410">"prijem tekstualnih poruka (WAP)"</string>
+ <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Dozvoljava aplikaciji da prima i obrađuje WAP poruke. Ova dozvola uključuje mogućnost praćenja ili brisanja poruka koje vam se šalju, a koje vam se ne prikazuju."</string>
+ <string name="permlab_getTasks" msgid="6466095396623933906">"preuzimanje pokrenutih aplikacija"</string>
+ <string name="permdesc_getTasks" msgid="7454215995847658102">"Dozvoljava aplikaciji da preuzima informacije o aktuelnim i nedavno pokrenutim zadacima. Ovo može da omogući aplikaciji da otkrije informacije o tome koje se aplikacije koriste na uređaju."</string>
+ <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"upravljanje vlasnicima profila i uređaja"</string>
+ <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"Dozvoljava aplikaciji da podesi vlasnike profila i vlasnika uređaja."</string>
+ <string name="permlab_reorderTasks" msgid="2018575526934422779">"promena redosleda pokrenutih aplikacija"</string>
+ <string name="permdesc_reorderTasks" msgid="7734217754877439351">"Dozvoljava aplikaciji da premešta zadatke u prvi plan i u pozadinu. Aplikacija može da radi ovo bez vašeg unosa."</string>
+ <string name="permlab_enableCarMode" msgid="5684504058192921098">"omogućavanje režima rada u automobilu"</string>
+ <string name="permdesc_enableCarMode" msgid="4853187425751419467">"Dozvoljava aplikaciji da omogući režim rada u automobilu."</string>
+ <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"zatvaranje drugih aplikacija"</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Dozvoljava aplikaciji da zaustavi pozadinske procese drugih aplikacija. Ovo može da zaustavi druge aplikacije."</string>
+ <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"prevlačenje preko drugih aplikacija"</string>
+ <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Dozvoljava aplikaciji da se prikazuje preko drugih aplikacija ili delova korisničkog interfejsa. To može da ometa upotrebu interfejsa pri radu sa drugim aplikacijama, a može i da izmeni stavke koje vidite na ekranu u drugim aplikacijama."</string>
+ <string name="permlab_persistentActivity" msgid="8841113627955563938">"omogućavanje neprekidne aktivnosti aplikacije"</string>
+ <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori tablet."</string>
+ <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Dozvoljava aplikaciji da neke svoje delove trajno zadrži u memoriji. To može da ograniči memoriju dostupnu drugim aplikacijama i uspori TV."</string>
+ <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori telefon."</string>
+ <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje prostora za skladištenje u aplikaciji"</string>
+ <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Dozvoljava aplikaciji da preuzme veličine kôda, podataka i keša."</string>
+ <string name="permlab_writeSettings" msgid="2226195290955224730">"izmena podešavanja sistema"</string>
+ <string name="permdesc_writeSettings" msgid="7775723441558907181">"Dozvoljava aplikaciji da menja podatke o podešavanju sistema. Zlonamerne aplikacije mogu da oštete konfiguraciju sistema."</string>
+ <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"pokretanje pri pokretanju sistema"</string>
+ <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Omogućava da se aplikacija pokrene odmah nakon pokretanja sistema. To može da uspori pokretanje tableta, pri čemu ova aplikacija može da uspori funkcionisanje celog tableta time što će uvek biti aktivna."</string>
+ <string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Dozvoljava aplikaciji da se pokrene čim se pokrene sistem. To može da uspori pokretanje TV-a, pri čemu ova aplikacija može da uspori funkcionisanje celog tableta time što će uvek biti aktivna."</string>
+ <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Omogućava da se aplikacija pokrene čim se sistem pokrene. To može da uspori pokretanje telefona, pri čemu ova aplikacija može da uspori funkcionisanje celog telefona time što će uvek biti aktivna."</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"slanje prijemčivih emitovanja"</string>
+ <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Dozvoljava aplikaciji da šalje prijemčiva emitovanja, koja ostaju po završetku emitovanja. Prekomerna upotreba može da uspori ili destabilizuje tablet tako što će ga primorati da troši previše memorije."</string>
+ <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Dozvoljava aplikaciji da šalje snimke emitovanja, koji ostaju i posle kraja emitovanja. Prekomerna upotreba može da uspori TV ili da mu ugrozi stabilnost jer koristi previše memorije."</string>
+ <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Dozvoljava aplikaciji da šalje prijemčiva emitovanja, koja ostaju po završetku emitovanja. Prekomerna upotreba može da uspori ili destabilizuje telefon tako što će ga primorati da troši previše memorije."</string>
+ <string name="permlab_readContacts" msgid="8348481131899886131">"čitanje kontakata"</string>
+ <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Dozvoljava aplikaciji da čita podatke o kontaktima uskladištene na tabletu, uključujući podatke o tome koliko često zovete određene osobe, šaljete im poruke e-pošte ili na drugi način komunicirate sa njima. Ova dozvola omogućava aplikacijama da čuvaju podatke o kontaktima, a zlonamerne aplikacije mogu da dele podatke o kontaktima bez vašeg znanja."</string>
+ <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Dozvoljava aplikaciji da čita podatke o kontaktima koje čuvate na TV-u, uključujući koliko često ste zvali, slali imejlove ili na druge načine komunicirali sa određenim osobama. Ova dozvola omogućava aplikacijama da čuvaju podatke o kontaktima, a zlonamerne aplikacije mogu da dele ove podatke bez vašeg znanja."</string>
+ <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Dozvoljava aplikaciji da čita podatke o kontaktima uskladištene na telefonu, uključujući podatke o tome koliko često zovete određene osobe, šaljete im poruke e-pošte ili na drugi način komunicirate sa njima. Ova dozvola omogućava aplikacijama da čuvaju podatke o kontaktima, a zlonamerne aplikacije mogu da dele podatke o kontaktima bez vašeg znanja."</string>
+ <string name="permlab_writeContacts" msgid="5107492086416793544">"izmena kontakata"</string>
+ <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Dozvoljava aplikaciji da menja podatke o kontaktima uskladištene na tabletu, uključujući podatke o tome koliko često zovete određene kontakte, šaljete im poruke e-pošte ili na drugi način komunicirate sa njima. Ova dozvola omogućava aplikacijama da brišu podatke o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Dozvoljava aplikaciji da menja podatke o kontaktima koje čuvate na TV-u, uključujući koliko često ste zvali, slali imejlove ili na druge načine komunicirali sa određenim kontaktima. Ova dozvola omogućava aplikacijama da brišu podatke o kontaktima."</string>
+ <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Dozvoljava aplikaciji da menja podatke o kontaktima uskladištene na telefonu, uključujući podatke o tome koliko često zovete određene kontakte, šaljete im poruke e-pošte ili na drugi način komunicirate sa njima. Ova dozvola omogućava aplikacijama da brišu podatke o kontaktima."</string>
+ <string name="permlab_readCallLog" msgid="3478133184624102739">"čitanje evidencije poziva"</string>
+ <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Dozvoljava aplikaciji da čita evidenciju poziva na tabletu, uključujući podatke o dolaznim i odlaznim pozivima. Ova dozvola omogućava aplikacijama da čuvaju podatke o evidenciji poziva, a zlonamerne aplikacije mogu da dele podatke o evidenciji poziva bez vašeg znanja."</string>
+ <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Dozvoljava aplikaciji da čita evidenciju poziva TV-a, uključujući podatke o dolaznim i odlaznim pozivima. Ova dozvola omogućava aplikacijama da čuvaju podatke iz evidencije poziva, a zlonamerne aplikacije mogu da dele te podatke bez vašeg znanja."</string>
+ <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Dozvoljava aplikaciji da čita evidenciju poziva na telefonu, uključujući podatke o dolaznim i odlaznim pozivima. Ova dozvola omogućava aplikacijama da čuvaju podatke o evidenciji poziva, a zlonamerne aplikacije mogu da dele podatke o evidenciji poziva bez vašeg znanja."</string>
+ <string name="permlab_writeCallLog" msgid="8552045664743499354">"pisanje evidencije poziva"</string>
+ <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Dozvoljava aplikaciji da menja evidenciju poziva na tabletu, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamerne aplikacije mogu ovo da koriste da bi brisale ili menjale evidenciju poziva."</string>
+ <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Dozvoljava aplikaciji da menja evidenciju poziva na TV-u, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamerne aplikacije mogu ovo da koriste da bi brisale ili menjale evidenciju poziva."</string>
+ <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Dozvoljava aplikaciji da menja evidenciju poziva na telefonu, uključujući podatke o dolaznim i odlaznim pozivima. Zlonamerne aplikacije mogu ovo da koriste da bi brisale ili menjale evidenciju poziva."</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"pristup senzorima na telu (poput monitora za praćenje pulsa)"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Dozvoljava aplikaciji da pristupa podacima sa senzora koji nadgledaju fizičku kondiciju, kao što je broj otkucaja srca."</string>
+ <string name="permlab_readCalendar" msgid="5972727560257612398">"čitanje kalendarskih događaja i poverljivih informacija"</string>
+ <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Dozvoljava aplikaciji da čita sve događaje kalendara uskladištene na tabletu, uključujući događaje prijatelja ili kolega. Ovo može da omogući aplikaciji da deli ili čuva podatke kalendara, bez obzira na poverljivost ili osetljivost."</string>
+ <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Dozvoljava aplikaciji da čita sve događaje iz kalendara koje čuvate na TV-u, uključujući i one koji pripadaju prijateljima ili kolegama. To može da dozvoli aplikaciji da deli ili čuva podatke iz kalendara, nezavisno od poverljivosti ili osetljivosti."</string>
+ <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Dozvoljava aplikaciji da čita sve događaje kalendara uskladištene na telefonu, uključujući događaje prijatelja ili kolega. Ovo može da omogući aplikaciji da deli ili čuva podatke kalendara, bez obzira na poverljivost ili osetljivost."</string>
+ <string name="permlab_writeCalendar" msgid="8438874755193825647">"dodavanje ili izmena kalendarskih događaja i slanje poruka e-pošte gostima bez znanja vlasnika"</string>
+ <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Dozvoljava aplikaciji da dodaje, uklanja i menja događaje koje možete da izmenite na tabletu, uključujući događaje prijatelja i kolega. Ovo može da omogući aplikaciji da šalje poruke koje izgledaju kao da ih šalju vlasnici kalendara ili menja događaje bez znanja vlasnika."</string>
+ <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Dozvoljava aplikaciji da dodaje, uklanja i menja događaje koje možete da izmenite na TV-u, uključujući događaje prijatelja ili kolega. Ovo može da dozvoli aplikaciji da šalje poruke koje izgledaju kao da ih šalju vlasnici kalendara ili da menja događaje bez znanja vlasnika."</string>
+ <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Dozvoljava aplikaciji da dodaje, uklanja i menja događaje koje možete da izmenite na telefonu, uključujući događaje prijatelja i kolega. Ovo može da omogući aplikaciji da šalje poruke koje izgledaju kao da ih šalju vlasnici kalendara ili menja događaje bez znanja vlasnika."</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"pristup dodatnim komandama dobavljača lokacije"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Omogućava aplikaciji da pristupa dodatnim komandama davaoca usluga lokacije. To može da omogući aplikaciji da utiče na rad GPS-a ili drugih izvora lokacije."</string>
+ <string name="permlab_accessFineLocation" msgid="251034415460950944">"pristup preciznoj lokaciji (utvrđena preko mreže i GPS-a)"</string>
+ <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Dozvoljava aplikaciji da preuzme precizne podatke o vašoj lokaciji pomoću globalnog sistema pozicioniranja (GPS) ili mrežnih izvora lokacija kao što su mobilni predajnici i Wi-Fi mreže. Ove usluge lociranja moraju da budu uključene i dostupne uređaju da bi aplikacija mogla da ih koristi. Aplikacije na osnovu ovoga mogu da odrede gde se približno nalazite i mogu dodatno da troše bateriju."</string>
+ <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"pristup približnoj lokaciji (utvrđena preko mreže)"</string>
+ <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Dozvoljava aplikaciji da preuzme podatke o vašoj približnoj lokaciji. Podatke o ovoj lokaciji obezbeđuju usluge lociranja pomoću mrežnih izvora lokacija kao što su mobilni predajnici i Wi-Fi mreže. Ove usluge lociranja moraju da budu uključene i dostupne uređaju da bi aplikacija mogla da ih koristi. Aplikacije na osnovu ovoga mogu da odrede gde se približno nalazite."</string>
+ <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"promena audio podešavanja"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Dozvoljava aplikaciji da menja globalna audio podešavanja kao što su jačina zvuka i izbor zvučnika koji se koristi kao izlaz."</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"snimanje audio zapisa"</string>
+ <string name="permdesc_recordAudio" msgid="4906839301087980680">"Dozvoljava aplikaciji da snima zvuk pomoću mikrofona. Ova dozvola omogućava aplikaciji da snima zvuk u bilo kom trenutku bez vaše potvrde."</string>
+ <string name="permlab_sim_communication" msgid="2935852302216852065">"slanje komandi na SIM"</string>
+ <string name="permdesc_sim_communication" msgid="5725159654279639498">"Omogućava aplikaciji da šalje komande SIM kartici. To je veoma opasno."</string>
+ <string name="permlab_camera" msgid="3616391919559751192">"snimanje fotografija i video snimaka"</string>
+ <string name="permdesc_camera" msgid="8497216524735535009">"Dozvoljava aplikaciji da snima slike i video snimke kamerom. Ova dozvola omogućava aplikaciji da u bilo kom trenutku koristi kameru bez vaše potvrde."</string>
+ <string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibracije"</string>
+ <string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji da kontroliše vibraciju."</string>
+ <string name="permlab_callPhone" msgid="3925836347681847954">"direktno pozivanje brojeva telefona"</string>
+ <string name="permdesc_callPhone" msgid="3740797576113760827">"Dozvoljava aplikaciji da poziva brojeve telefona bez vaše dozvole. Ovo može da dovede do neočekivanih troškova ili poziva. Imajte na umu da ovo ne dozvoljava aplikaciji da poziva brojeve za hitne slučajeve. Zlonamerne aplikacije mogu da pozivaju bez vaše potvrde, što može da dovede do troškova."</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi poziva pomoću razmene trenutnih poruka"</string>
+ <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Dozvoljava aplikaciji da koristi uslugu razmene trenutnih poruka da bi upućivala pozive bez vaše intervencije."</string>
+ <string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
+ <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Dozvoljava aplikaciji da pristupa funkcijama telefona na uređaju. Ova dozvola omogućava aplikaciji da utvrdi broj telefona i ID-ove uređaja, zatim da li je poziv aktivan, kao i broj daljinskog uređaja sa kojim je uspostavljen poziv."</string>
+ <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"sprečavanje prelaska tableta u stanje spavanja"</string>
+ <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"sprečavanje TV-a da pređe u stanje spavanja"</string>
+ <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečavanje prelaska telefona u stanje spavanja"</string>
+ <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Dozvoljava aplikaciji da spreči tablet da pređe u stanje spavanja."</string>
+ <string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Dozvoljava aplikaciji da spreči TV da pređe u stanje spavanja."</string>
+ <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"Dozvoljava aplikaciji da spreči telefon da pređe u stanje spavanja."</string>
+ <string name="permlab_transmitIr" msgid="7545858504238530105">"prenos infracrvenih zraka"</string>
+ <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"Dozvoljava aplikaciji da koristi odašiljač infracrvenih zraka tableta."</string>
+ <string name="permdesc_transmitIr" product="tv" msgid="3926790828514867101">"Dozvoljava aplikaciji da koristi odašiljač infracrvenih zraka TV-a."</string>
+ <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"Dozvoljava aplikaciji da koristi odašiljač infracrvenih zraka telefona."</string>
+ <string name="permlab_setWallpaper" msgid="6627192333373465143">"podešavanje pozadine"</string>
+ <string name="permdesc_setWallpaper" msgid="7373447920977624745">"Dozvoljava aplikaciji da postavlja pozadinu sistema."</string>
+ <string name="permlab_setWallpaperHints" msgid="3278608165977736538">"prilagođavanje veličine pozadine"</string>
+ <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Dozvoljava aplikaciji da podesi savete za sistemsku veličinu pozadine."</string>
+ <string name="permlab_setTimeZone" msgid="2945079801013077340">"podešavanje vremenske zone"</string>
+ <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Dozvoljava aplikaciji da promeni vremensku zonu tableta."</string>
+ <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Dozvoljava aplikaciji da promeni vremensku zonu TV-a."</string>
+ <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Dozvoljava aplikaciji da promeni vremensku zonu telefona."</string>
+ <string name="permlab_getAccounts" msgid="1086795467760122114">"pronalaženje naloga na uređaju"</string>
+ <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Dozvoljava aplikaciji da preuzima listu naloga poznatih tabletu. Ovo može da obuhvata bilo koje naloge koje prave aplikacije koje instalirate."</string>
+ <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Dozvoljava aplikaciji da dođe do liste naloga poznatih TV-u. Tu mogu da spadaju nalozi koje su otvorile aplikacije koje ste instalirali."</string>
+ <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Dozvoljava aplikaciji da preuzima listu naloga poznatih telefonu. Ovo može da obuhvata bilo koje naloge koje prave aplikacije koje instalirate."</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"pregled mrežnih veza"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Dozvoljava aplikaciji da pregleda informacije o mrežnim vezama kao što su informacije o tome koje mreže postoje i koje mreže su povezane."</string>
+ <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"ima pun mrežni pristup"</string>
+ <string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Dozvoljava aplikaciji da pravi mrežne priključke i koristi prilagođene mrežne protokole. Pregledač i druge aplikacije omogućavaju slanje podataka na Internet, pa ova dozvola nije potrebna za slanje podataka na Internet."</string>
+ <string name="permlab_changeNetworkState" msgid="958884291454327309">"promena veze sa mrežom"</string>
+ <string name="permdesc_changeNetworkState" msgid="6789123912476416214">"Dozvoljava aplikaciji da menja status povezivanja sa mrežom."</string>
+ <string name="permlab_changeTetherState" msgid="5952584964373017960">"promena povezivanja privezivanjem"</string>
+ <string name="permdesc_changeTetherState" msgid="1524441344412319780">"Dozvoljava aplikaciji da menja status veze sa privezanom mrežom."</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"pregled Wi-Fi veza"</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"Dozvoljava aplikaciji da pregleda informacije o Wi-Fi umrežavanju, kao što su informacije o tome da li je Wi-Fi omogućen i nazivi povezanih Wi-Fi uređaja."</string>
+ <string name="permlab_changeWifiState" msgid="6550641188749128035">"povezivanje i prekid veze sa Wi-Fi mrežom"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"Dozvoljava aplikaciji da se povezuje sa pristupnim tačkama za Wi-Fi i prekida vezu sa njima, kao i da unosi promene u konfiguraciju uređaja za Wi-Fi mreže."</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"omogućavanje prijema višesmernog Wi-Fi saobraćaja"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Dozvoljava aplikaciji da prima pakete koji se šalju na sve uređaje na Wi-Fi mreži pomoću višesmernih adresa, a ne samo na tablet. Koristi više napajanja od režima jednosmernog saobraćaja."</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Dozvoljava aplikaciji da prima pakete poslate svim uređajima na Wi-Fi mreži pomoću adresa za višestruko prebacivanje, ne samo TV-u. Koristi više energije nego režim bez višestrukog prebacivanja."</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Dozvoljava aplikaciji da prima pakete koji se šalju na sve uređaje na Wi-Fi mreži pomoću višesmernih adresa, a ne samo na telefon. Koristi više napajanja od režima jednosmernog saobraćaja."</string>
+ <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"pristup Bluetooth podešavanjima"</string>
+ <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Dozvoljava aplikaciji da konfiguriše lokalni Bluetooth tablet, kao i da otkrije daljinske uređaje i upari se sa njima."</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Dozvoljava aplikaciji da konfiguriše lokalni Bluetooth TV, kao i da otkriva udaljene uređaje i uparuje se sa njima."</string>
+ <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Dozvoljava aplikaciji da konfiguriše lokalni Bluetooth telefon, kao i da otkrije daljinske uređaje i upari se sa njima."</string>
+ <string name="permlab_accessWimaxState" msgid="4195907010610205703">"povezivanje i prekid veze sa WiMAX-om"</string>
+ <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Dozvoljava aplikaciji da utvrdi da li je WiMAX omogućen, kao i informacije o bilo kojim povezanim WiMAX mrežama."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"promeni WiMAX statusa"</string>
+ <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Dozvoljava aplikaciji da povezuje tablet sa WiMAX mrežama i prekida veze sa njima."</string>
+ <string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Dozvoljava aplikaciji da povezuje TV sa WiMAX mrežama i da raskida tu vezu."</string>
+ <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Dozvoljava aplikaciji da povezuje telefon sa WiMAX mrežama i prekida veze sa njima."</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje sa Bluetooth uređajima"</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Dozvoljava aplikaciji da pregleda konfiguraciju Bluetooth-a na tabletu, kao i da uspostavlja i prihvata veze sa uparenim uređajima."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Dozvoljava aplikaciji da vidi konfiguraciju Bluetooth-a na TV-u, kao i da uspostavlja i prihvata veze sa uparenim uređajima."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Dozvoljava aplikaciji da pregleda konfiguraciju Bluetooth-a na telefonu, kao i da uspostavlja i prihvata veze sa uparenim uređajima."</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"kontrola komunikacije u užem polju (Near Field Communication)"</string>
+ <string name="permdesc_nfc" msgid="7120611819401789907">"Dozvoljava aplikaciji da komunicira sa oznakama, karticama i čitačima komunikacije kratkog dometa (NFC)."</string>
+ <string name="permlab_disableKeyguard" msgid="3598496301486439258">"onemogućavanje zaključavanja ekrana"</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Dozvoljava aplikaciji da onemogući zaključavanje tastature i sve povezane bezbednosne mere sa lozinkama. Na primer, telefon onemogućava zaključavanje tastature pri prijemu dolaznog telefonskog poziva, a zatim ga ponovo omogućava po završetku poziva."</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"upravljaj hardverom za otiske prstiju"</string>
+ <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Dozvoljava aplikaciji da aktivira metode za dodavanje i brisanje šablona otisaka prstiju koji će se koristiti."</string>
+ <string name="permlab_useFingerprint" msgid="3150478619915124905">"koristi hardver za otiske prstiju"</string>
+ <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Dozvoljava aplikaciji da koristi hardver za otiske prstiju radi potvrde autentičnosti"</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Pokušajte ponovo."</string>
+ <string-array name="fingerprint_acquired_vendor">
+ </string-array>
+ <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
+ <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
+ <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
+ <string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
+ <string-array name="fingerprint_error_vendor">
+ </string-array>
+ <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona otiska prsta"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"čitanje podešavanja sinhronizacije"</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Dozvoljava aplikaciji da čita podešavanja sinhronizacije za nalog. Na primer, ovako može da se utvrdi da li je aplikacija Ljudi sinhronizovana sa nalogom."</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"uključivanje i isključivanje sinhronizacije"</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Dozvoljava aplikaciji da menja podešavanja sinhronizacije za nalog. Na primer, ovako može da se omogući sinhronizacija aplikacije Ljudi sa nalogom."</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"čitanje statistike o sinhronizaciji"</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Dozvoljava aplikaciji da čita statistiku sinhronizacije za nalog, uključujući istoriju sinhronizovanih događaja i količinu podataka koji se sinhronizuju."</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"čitanje sadržaja USB memorije"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"čitanje sadržaja SD kartice"</string>
+ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Omogućava aplikaciji da čita sadržaj USB memorije."</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Omogućava aplikaciji da čita sadržaj SD kartice."</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmena ili brisanje sadržaja USB memorije"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"menjanje ili brisanje sadržaja SD kartice"</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Dozvoljava aplikaciji da upisuje podatke na USB memoriju."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Dozvoljava aplikaciji da upisuje podatke na SD karticu."</string>
+ <string name="permlab_use_sip" msgid="2052499390128979920">"upućivanje/prijem SIP poziva"</string>
+ <string name="permdesc_use_sip" msgid="2297804849860225257">"Omogućava aplikaciji da upućuje i prima SIP pozive."</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"registruje nove veze sa telekomunikacionim mrežama preko SIM kartice"</string>
+ <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Dozvoljava aplikaciji da registruje nove veze sa telekomunikacionim mrežama preko SIM kartice."</string>
+ <string name="permlab_register_call_provider" msgid="108102120289029841">"registruje nove veze sa telekomunikacionim mrežama"</string>
+ <string name="permdesc_register_call_provider" msgid="7034310263521081388">"Dozvoljava aplikaciji da registruje nove veze sa telekomunikacionim mrežama."</string>
+ <string name="permlab_connection_manager" msgid="1116193254522105375">"upravljanje vezama sa telekomunikacionim mrežama"</string>
+ <string name="permdesc_connection_manager" msgid="5925480810356483565">"Dozvoljava aplikaciji da upravlja vezama sa telekomunikacionim mrežama."</string>
+ <string name="permlab_bind_incall_service" msgid="6773648341975287125">"komuniciraj sa ekranom tokom poziva"</string>
+ <string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Dozvoljava aplikaciji da kontroliše kada i kako se korisniku prikazuje ekran tokom poziva."</string>
+ <string name="permlab_bind_connection_service" msgid="3557341439297014940">"da stupa u interakciju sa telefonskim uslugama"</string>
+ <string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Dozvoljava interakciju aplikacije sa telefonskim uslugama radi upućivanja/primanja poziva."</string>
+ <string name="permlab_control_incall_experience" msgid="9061024437607777619">"pružaj korisnički doživljaj tokom poziva"</string>
+ <string name="permdesc_control_incall_experience" msgid="915159066039828124">"Dozvoljava aplikaciji da pruža korisnički doživljaj tokom poziva."</string>
+ <string name="permlab_readNetworkUsageHistory" msgid="7862593283611493232">"čita istoriju korišćenja mreže"</string>
+ <string name="permdesc_readNetworkUsageHistory" msgid="7689060749819126472">"Dozvoljava aplikaciji da čita istoriju korišćenja mreže za posebne mreže i aplikacije."</string>
+ <string name="permlab_manageNetworkPolicy" msgid="2562053592339859990">"upravljanje smernicama za mrežu"</string>
+ <string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"Dozvoljava aplikaciji da upravlja smernicama za mrežu i određuje posebna pravila za aplikaciju."</string>
+ <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"izmenite obračunavanje korišćenja mreže"</string>
+ <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"Dozvoljava aplikaciji da izmeni način na koji aplikacije koriste mrežu. Ne koriste je uobičajene aplikacije."</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"pristup obaveštenjima"</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"Dozvoljava aplikaciji da preuzima, ispituje i briše obaveštenja, uključujući ona koja postavljaju druge aplikacije."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"povezivanje sa uslugom monitora obaveštenja"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Dozvoljava vlasniku da se poveže sa interfejsom usluge monitora obaveštenja najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
+ <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"poveži sa uslugom dobavljača uslova"</string>
+ <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Dozvoljava vlasniku da se poveže sa interfejsom najvišeg nivoa usluge dobavljača uslova. Ne bi trebalo nikada da bude potrebno za uobičajene aplikacije."</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"povezivanje sa uslugom sanjarenja"</string>
+ <string name="permdesc_bindDreamService" msgid="7325825272223347863">"Dozvoljava vlasniku da se poveže sa interfejsom usluge sanjarenja najvišeg nivoa. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
+ <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"pozivanje aplikacije sa konfiguracijom koju određuje operater"</string>
+ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dozvoljava vlasniku da poziva aplikaciju sa konfiguracijom koju određuje operater. Uobičajene aplikacije nikada ne bi trebalo da je koriste."</string>
+ <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje podataka o uslovima na mreži"</string>
+ <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Dozvoljava aplikaciji da prati podatke o uslovima na mreži. Ne bi nikada trebalo da bude potrebno za normalne aplikacije."</string>
+ <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promeni kalibraciju ulaznog uređaja"</string>
+ <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Dozvoljava aplikaciji da modifikuje parametre kalibracije dodirnog ekrana. Ne bi trebalo da bude potrebno za normalne aplikacije."</string>
+ <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"pristup DRM sertifikatima"</string>
+ <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"Dozvoljava aplikaciji da dodeljuje i koristi DRM sertifikate. Nikada ne bi trebalo da se koristi za uobičajene aplikacije."</string>
+ <string name="permlab_handoverStatus" msgid="7820353257219300883">"prijem statusa prebacivanja pomoću Android prebacivanja"</string>
+ <string name="permdesc_handoverStatus" msgid="4788144087245714948">"Dozvoljava ovoj aplikaciji da prima informacije o aktuelnim prebacivanjima pomoću Android prebacivanja"</string>
+ <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"uklanjaj DRM sertifikate"</string>
+ <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Dozvoljava aplikaciji da uklanja DRM sertifikate. Nikada ne bi trebalo da se koristi za obične aplikacije."</string>
+ <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"povezivanje sa uslugom za razmenu poruka mobilnog operatera"</string>
+ <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dozvoljava vlasniku da se poveže sa interfejsom najvišeg nivoa za uslugu za razmenu poruka mobilnog operatera. Nikada ne bi trebalo da bude potrebno za standardne aplikacije."</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"povezivanje sa uslugama operatera"</string>
+ <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Dozvoljava vlasniku da se poveže sa uslugama operatera. Nikada ne bi trebalo da bude potrebno za obične aplikacije."</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"pristupaj podešavanju Ne uznemiravaj"</string>
+ <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Dozvoljava aplikaciji da čita i upisuje konfiguraciju podešavanja Ne uznemiravaj."</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"Podešavanje pravila za lozinku"</string>
+ <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontroliše dužinu i znakove dozvoljene u lozinkama i PIN-ovima za zaključavanje ekrana."</string>
+ <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledanje pokušaja otključavanja ekrana"</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"Prati broj netačno unetih lozinki prilikom otključavanja ekrana i zaključava tablet ili briše podatke sa tableta ako je netačna lozinka uneta previše puta."</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"Nadgleda broj netačnih lozinki koje unesete pri otključavanju ekrana i zaključava TV ili briše sve podatke sa njega ako se unese previše netačnih lozinki."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"Prati broj netačno unetih lozinki pri otključavanju ekrana i zaključava telefon ili briše sve podatke sa telefona ako je netačna lozinka uneta previše puta."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava tablet ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava TV ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Nadgleda broj netačnih lozinki unetih pri otključavanju ekrana i zaključava telefon ili briše sve podatke ovog korisnika ako se unese previše netačnih lozinki."</string>
+ <string name="policylab_resetPassword" msgid="4934707632423915395">"Promena zaključavanja ekrana"</string>
+ <string name="policydesc_resetPassword" msgid="1278323891710619128">"Promenite zaključavanje ekrana."</string>
+ <string name="policylab_forceLock" msgid="2274085384704248431">"Zaključavanje ekrana"</string>
+ <string name="policydesc_forceLock" msgid="1141797588403827138">"Kontrolišite način i vreme zaključavanja ekrana."</string>
+ <string name="policylab_wipeData" msgid="3910545446758639713">"Brisanje svih podataka"</string>
+ <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Brisanje podataka na tabletu bez upozorenja resetovanjem na fabrička podešavanja."</string>
+ <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Briše sve podatke sa TV-a bez upozorenja resetovanjem na fabrička podešavanja."</string>
+ <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Izbrišite podatke na telefonu bez upozorenja resetovanjem na fabrička podešavanja."</string>
+ <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Obriši podatke korisnika"</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Briše podatke ovog korisnika na ovom tabletu bez upozorenja."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Briše podatke ovog korisnika na ovom TV-u bez upozorenja."</string>
+ <string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"Briše podatke ovog korisnika na ovom telefonu bez upozorenja."</string>
+ <string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Podesite globalni proksi server uređaja"</string>
+ <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"Podešava globalni proksi uređaja koji će se koristiti dok su smernice omogućene. Samo vlasnik uređaja može da podesi globalni proksi."</string>
+ <string name="policylab_expirePassword" msgid="5610055012328825874">"Podesi istek. lozin. za zaklj. ekr."</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"Menja koliko često lozinka, PIN ili šablon za zaključavanje ekrana mora da se menja."</string>
+ <string name="policylab_encryptedStorage" msgid="8901326199909132915">"Podešavanje šifrovanja skladišta"</string>
+ <string name="policydesc_encryptedStorage" msgid="2637732115325316992">"Zahteva da sačuvani podaci aplikacije budu šifrovani."</string>
+ <string name="policylab_disableCamera" msgid="6395301023152297826">"Onemogućavanje kamera"</string>
+ <string name="policydesc_disableCamera" msgid="2306349042834754597">"Sprečite korišćenje svih kamera uređaja."</string>
+ <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Onemogućava neke funk. zaključavanja ekrana"</string>
+ <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Sprečava korišćenje nekih funkcija zaključavanja ekrana."</string>
+ <string-array name="phoneTypes">
+ <item msgid="8901098336658710359">"Kuća"</item>
+ <item msgid="869923650527136615">"Mobilni"</item>
+ <item msgid="7897544654242874543">"Posao"</item>
+ <item msgid="1103601433382158155">"Faks na poslu"</item>
+ <item msgid="1735177144948329370">"Faks kod kuće"</item>
+ <item msgid="603878674477207394">"Pejdžer"</item>
+ <item msgid="1650824275177931637">"Drugo"</item>
+ <item msgid="9192514806975898961">"Prilagođeno"</item>
+ </string-array>
+ <string-array name="emailAddressTypes">
+ <item msgid="8073994352956129127">"Kuća"</item>
+ <item msgid="7084237356602625604">"Posao"</item>
+ <item msgid="1112044410659011023">"Drugo"</item>
+ <item msgid="2374913952870110618">"Prilagođeno"</item>
+ </string-array>
+ <string-array name="postalAddressTypes">
+ <item msgid="6880257626740047286">"Kuća"</item>
+ <item msgid="5629153956045109251">"Posao"</item>
+ <item msgid="4966604264500343469">"Drugo"</item>
+ <item msgid="4932682847595299369">"Prilagođeno"</item>
+ </string-array>
+ <string-array name="imAddressTypes">
+ <item msgid="1738585194601476694">"Kuća"</item>
+ <item msgid="1359644565647383708">"Posao"</item>
+ <item msgid="7868549401053615677">"Drugo"</item>
+ <item msgid="3145118944639869809">"Prilagođeno"</item>
+ </string-array>
+ <string-array name="organizationTypes">
+ <item msgid="7546335612189115615">"Posao"</item>
+ <item msgid="4378074129049520373">"Drugo"</item>
+ <item msgid="3455047468583965104">"Prilagođeno"</item>
+ </string-array>
+ <string-array name="imProtocols">
+ <item msgid="8595261363518459565">"AIM"</item>
+ <item msgid="7390473628275490700">"Windows Live"</item>
+ <item msgid="7882877134931458217">"Yahoo"</item>
+ <item msgid="5035376313200585242">"Skype"</item>
+ <item msgid="7532363178459444943">"QQ"</item>
+ <item msgid="3713441034299660749">"Google Talk"</item>
+ <item msgid="2506857312718630823">"ICQ"</item>
+ <item msgid="1648797903785279353">"Jabber"</item>
+ </string-array>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"Prilagođeno"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"Kuća"</string>
+ <string name="phoneTypeMobile" msgid="6501463557754751037">"Mobilni"</string>
+ <string name="phoneTypeWork" msgid="8863939667059911633">"Posao"</string>
+ <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Faks na poslu"</string>
+ <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Faks kod kuće"</string>
+ <string name="phoneTypePager" msgid="7582359955394921732">"Pejdžer"</string>
+ <string name="phoneTypeOther" msgid="1544425847868765990">"Drugo"</string>
+ <string name="phoneTypeCallback" msgid="2712175203065678206">"Povratni poziv"</string>
+ <string name="phoneTypeCar" msgid="8738360689616716982">"Automobil"</string>
+ <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Poslovni glavni"</string>
+ <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
+ <string name="phoneTypeMain" msgid="6766137010628326916">"Glavni"</string>
+ <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Drugi faks"</string>
+ <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
+ <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
+ <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
+ <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Broj poslovnog mobilnog telefona"</string>
+ <string name="phoneTypeWorkPager" msgid="649938731231157056">"Poslovni pejdžer"</string>
+ <string name="phoneTypeAssistant" msgid="5596772636128562884">"Pomoćnik"</string>
+ <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"Prilagođeno"</string>
+ <string name="eventTypeBirthday" msgid="2813379844211390740">"Rođendan"</string>
+ <string name="eventTypeAnniversary" msgid="3876779744518284000">"Godišnjica"</string>
+ <string name="eventTypeOther" msgid="7388178939010143077">"Drugi"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Prilagođeno"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"Kuća"</string>
+ <string name="emailTypeWork" msgid="3548058059601149973">"Posao"</string>
+ <string name="emailTypeOther" msgid="2923008695272639549">"Drugo"</string>
+ <string name="emailTypeMobile" msgid="119919005321166205">"Mobilni"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"Prilagođeno"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"Kuća"</string>
+ <string name="postalTypeWork" msgid="5268172772387694495">"Posao"</string>
+ <string name="postalTypeOther" msgid="2726111966623584341">"Drugo"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"Prilagođeno"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"Kuća"</string>
+ <string name="imTypeWork" msgid="1371489290242433090">"Posao"</string>
+ <string name="imTypeOther" msgid="5377007495735915478">"Drugo"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"Prilagođeno"</string>
+ <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
+ <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
+ <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
+ <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
+ <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
+ <string name="imProtocolGoogleTalk" msgid="493902321140277304">"Hangouts"</string>
+ <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
+ <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
+ <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
+ <string name="orgTypeWork" msgid="29268870505363872">"Posao"</string>
+ <string name="orgTypeOther" msgid="3951781131570124082">"Drugo"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"Prilagođeno"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"Prilagođeno"</string>
+ <string name="relationTypeAssistant" msgid="6274334825195379076">"Pomoćnik"</string>
+ <string name="relationTypeBrother" msgid="8757913506784067713">"Brat"</string>
+ <string name="relationTypeChild" msgid="1890746277276881626">"Dete"</string>
+ <string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Nevenčani partner"</string>
+ <string name="relationTypeFather" msgid="5228034687082050725">"Otac"</string>
+ <string name="relationTypeFriend" msgid="7313106762483391262">"Prijatelj"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Menadžer"</string>
+ <string name="relationTypeMother" msgid="4578571352962758304">"Majka"</string>
+ <string name="relationTypeParent" msgid="4755635567562925226">"Roditelj"</string>
+ <string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
+ <string name="relationTypeReferredBy" msgid="101573059844135524">"Uputio/la"</string>
+ <string name="relationTypeRelative" msgid="1799819930085610271">"Rođak"</string>
+ <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
+ <string name="relationTypeSpouse" msgid="394136939428698117">"Suprug/a"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Prilagođeno"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Početna"</string>
+ <string name="sipAddressTypeWork" msgid="6920725730797099047">"Posao"</string>
+ <string name="sipAddressTypeOther" msgid="4408436162950119849">"Drugi"</string>
+ <string name="quick_contacts_not_available" msgid="746098007828579688">"Nije pronađena nijedna aplikacija za prikaz ovog kontakta."</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN kôd"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN kôd"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kôd"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN kôd"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite da biste uneli lozinku"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Otkucajte lozinku da biste otključali"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kôd je netačan."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Da biste otključali, pritisnite „Meni“, a zatim 0."</string>
+ <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Broj za hitne slučajeve"</string>
+ <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Mobilna mreža nije dostupna"</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran je zaključan."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Pritisnite „Meni“ za otključavanje."</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Unesite šablon za otključavanje"</string>
+ <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Hitne službe"</string>
+ <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Nazad na poziv"</string>
+ <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Tačno!"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
+ <string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je najveći dozvoljeni broj pokušaja Otključavanja licem"</string>
+ <string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
+ <string name="lockscreen_missing_sim_message" product="tablet" msgid="151659196095791474">"U tabletu nema SIM kartice."</string>
+ <string name="lockscreen_missing_sim_message" product="tv" msgid="1943633865476989599">"U TV-u nema SIM kartice."</string>
+ <string name="lockscreen_missing_sim_message" product="default" msgid="2186920585695169078">"U telefon nije umetnuta SIM kartica."</string>
+ <string name="lockscreen_missing_sim_instructions" msgid="5372787138023272615">"Umetnite SIM karticu."</string>
+ <string name="lockscreen_missing_sim_instructions_long" msgid="3526573099019319472">"SIM nedostaje ili ne može da se pročita. Umetnite SIM karticu."</string>
+ <string name="lockscreen_permanent_disabled_sim_message_short" msgid="5096149665138916184">"SIM kartica je neupotrebljiva."</string>
+ <string name="lockscreen_permanent_disabled_sim_instructions" msgid="910904643433151371">"SIM kartica je trajno onemogućena.\n Obratite se dobavljaču usluge bežične mreže da biste dobili drugu SIM karticu."</string>
+ <string name="lockscreen_transport_prev_description" msgid="6300840251218161534">"Prethodna pesma"</string>
+ <string name="lockscreen_transport_next_description" msgid="573285210424377338">"Sledeća pesma"</string>
+ <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"Pauza"</string>
+ <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"Pusti"</string>
+ <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Zaustavi"</string>
+ <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Premotaj unazad"</string>
+ <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Premotaj unapred"</string>
+ <string name="emergency_calls_only" msgid="6733978304386365407">"Samo hitni pozivi"</string>
+ <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Mreža je zaključana"</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM kartica je zaključana PUK kodom."</string>
+ <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte Korisnički vodič ili kontaktirajte Korisničku podršku."</string>
+ <string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
+ <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice…"</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Nepravilno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Neispravno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste šablon?"</string>
+ <string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Otključavanje naloga"</string>
+ <string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Previše pokušaja unosa šablona"</string>
+ <string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Da biste otključali, prijavite se pomoću Google naloga."</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Korisničko ime (imejl adresa)"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Lozinka"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Prijavi me"</string>
+ <string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nevažeće korisničko ime ili lozinka."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Zaboravili ste korisničko ime ili lozinku?\nPosetite adresu "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Proveravanje..."</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"Otključaj"</string>
+ <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Uključi zvuk"</string>
+ <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Isključi zvuk"</string>
+ <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Obrazac je započet"</string>
+ <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Obrazac je obrisan"</string>
+ <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Ćelija je dodata"</string>
+ <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Ćelija <xliff:g id="CELL_INDEX">%1$s</xliff:g> je dodata"</string>
+ <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Obrazac je dovršen"</string>
+ <string name="lockscreen_access_pattern_area" msgid="400813207572953209">"Oblast šablona."</string>
+ <string name="keyguard_accessibility_widget_changed" msgid="5678624624681400191">"%1$s. Vidžet %2$d od %3$d."</string>
+ <string name="keyguard_accessibility_add_widget" msgid="8273277058724924654">"Dodaj vidžet."</string>
+ <string name="keyguard_accessibility_widget_empty_slot" msgid="1281505703307930757">"Prazno"</string>
+ <string name="keyguard_accessibility_unlock_area_expanded" msgid="2278106022311170299">"Oblast otključavanja je proširena."</string>
+ <string name="keyguard_accessibility_unlock_area_collapsed" msgid="6366992066936076396">"Oblast otključavanja je skupljena."</string>
+ <string name="keyguard_accessibility_widget" msgid="6527131039741808240">"Vidžet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g>."</string>
+ <string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Izbor korisnika"</string>
+ <string name="keyguard_accessibility_status" msgid="8008264603935930611">"Status"</string>
+ <string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Kontrole za medije"</string>
+ <string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Započela je promena redosleda vidžeta."</string>
+ <string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Promena redosleda vidžeta je završena."</string>
+ <string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"Vidžet <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> je izbrisan."</string>
+ <string name="keyguard_accessibility_expand_lock_area" msgid="519859720934178024">"Proširi oblast otključavanja."</string>
+ <string name="keyguard_accessibility_slide_unlock" msgid="2959928478764697254">"Otključavanje prevlačenjem."</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Otključavanje šablonom."</string>
+ <string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje PIN-om."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblast šablona."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast prevlačenja."</string>
+ <string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string>
+ <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string>
+ <string name="granularity_label_character" msgid="7336470535385009523">"znak"</string>
+ <string name="granularity_label_word" msgid="7075570328374918660">"reč"</string>
+ <string name="granularity_label_link" msgid="5815508880782488267">"veza"</string>
+ <string name="granularity_label_line" msgid="5764267235026120888">"red"</string>
+ <string name="factorytest_failed" msgid="5410270329114212041">"Fabričko testiranje nije uspelo"</string>
+ <string name="factorytest_not_system" msgid="4435201656767276723">"Radnja FACTORY_TEST je podržana samo za pakete instalirane u direktorijumu /system/app."</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"Nije pronađen nijedan paket koji obezbeđuje radnju FACTORY_TEST."</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"Ponovo pokreni"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"Na stranici na adresi „<xliff:g id="TITLE">%s</xliff:g>“ piše sledeće:"</string>
+ <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
+ <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Potvrda navigacije"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Zatvori ovu stranicu"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Ostani na ovoj stranici"</string>
+ <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nDa li stvarno želite da napustite ovu stranicu?"</string>
+ <string name="save_password_label" msgid="6860261758665825069">"Potvrda"</string>
+ <string name="double_tap_toast" msgid="4595046515400268881">"Savet: Dodirnite dvaput da biste uvećali i umanjili prikaz."</string>
+ <string name="autofill_this_form" msgid="4616758841157816676">"Autom. pop."</string>
+ <string name="setup_autofill" msgid="7103495070180590814">"Podeš. aut. pop."</string>
+ <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
+ <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
+ <string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
+ <string name="autofill_province" msgid="2231806553863422300">"Pokrajina"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"Poštanski broj"</string>
+ <string name="autofill_state" msgid="6988894195520044613">"Država"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"Poštanski broj"</string>
+ <string name="autofill_county" msgid="237073771020362891">"Okrug"</string>
+ <string name="autofill_island" msgid="4020100875984667025">"Ostrvo"</string>
+ <string name="autofill_district" msgid="8400735073392267672">"Distrikt"</string>
+ <string name="autofill_department" msgid="5343279462564453309">"Odeljenje"</string>
+ <string name="autofill_prefecture" msgid="2028499485065800419">"Prefektura"</string>
+ <string name="autofill_parish" msgid="8202206105468820057">"Parohija"</string>
+ <string name="autofill_area" msgid="3547409050889952423">"Oblast"</string>
+ <string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
+ <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"čitanje veb obeleživača i istorije"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Dozvoljava aplikaciji da čita istoriju svih URL adresa koje su posećene pomoću Pregledača, kao i sve obeleživače u Pregledaču. Napomena: Ova dozvola se možda na primenjuje na pregledače treće strane i druge aplikacije sa mogućnošću veb pregledanja."</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"pisanje veb obeleživača i istorije"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Dozvoljava aplikaciji da menja istoriju Pregledača ili obeleživače uskladištene na tabletu. Ovo može da omogući aplikaciji da briše ili menja podatke Pregledača. Napomena: Ova dozvola se možda na primenjuje na pregledače treće strane i druge aplikacije sa mogućnošću veb pregledanja."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Dozvoljava aplikaciji da menja istoriju pregledača ili obeleživače koje čuvate na TV-u. To može da dozvoli aplikaciji da briše ili menja podatke pregledača. Napomena: Ova dozvola se možda ne primenjuje na pregledače treće strane i druge aplikacije sa mogućnošću pregledanja veba."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Dozvoljava aplikaciji da menja istoriju Pregledača ili obeleživače uskladištene na telefonu. Ovo može da omogući aplikaciji da briše ili menja podatke Pregledača. Napomena: Ova dozvola se možda na primenjuje na pregledače treće strane i druge aplikacije sa mogućnošću veb pregledanja."</string>
+ <string name="permlab_setAlarm" msgid="1379294556362091814">"podešavanje alarma"</string>
+ <string name="permdesc_setAlarm" msgid="316392039157473848">"Dozvoljava aplikaciji da podesi alarm u instaliranoj aplikaciji budilnika. Neke aplikacije budilnika možda ne primenjuju ovu funkciju."</string>
+ <string name="permlab_addVoicemail" msgid="5525660026090959044">"dodavanje govorne pošte"</string>
+ <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Dozvoljava aplikaciji da dodaje poruke u prijemno sanduče govorne pošte."</string>
+ <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"izmena dozvola za geografske lokacije Pregledača"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Dozvoljava aplikaciji da izmeni dozvole Pregledača za utvrđivanje geografske lokacije. Zlonamerne aplikacije to mogu da zloupotrebe i iskoriste za slanje informacija o lokaciji nasumičnim veb sajtovima."</string>
+ <string name="save_password_message" msgid="767344687139195790">"Želite li da pregledač zapamti ovu lozinku?"</string>
+ <string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
+ <string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Nikad"</string>
+ <string name="open_permission_deny" msgid="7374036708316629800">"Nemate dozvolu da otvorite ovu stranicu."</string>
+ <string name="text_copied" msgid="4985729524670131385">"Tekst je kopiran u privremenu memoriju."</string>
+ <string name="more_item_label" msgid="4650918923083320495">"Još"</string>
+ <string name="prepend_shortcut_label" msgid="2572214461676015642">"Meni+"</string>
+ <string name="menu_space_shortcut_label" msgid="2410328639272162537">"razmak"</string>
+ <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
+ <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"izbriši"</string>
+ <string name="search_go" msgid="8298016669822141719">"Pretraži"</string>
+ <string name="search_hint" msgid="1733947260773056054">"Pretražite…"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"Pretraži"</string>
+ <string name="searchview_description_query" msgid="5911778593125355124">"Upit za pretragu"</string>
+ <string name="searchview_description_clear" msgid="1330281990951833033">"Obriši upit"</string>
+ <string name="searchview_description_submit" msgid="2688450133297983542">"Pošalji upit"</string>
+ <string name="searchview_description_voice" msgid="2453203695674994440">"Glasovna pretraga"</string>
+ <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Omogućiti Istraživanje dodirom?"</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi da omogući Istraživanje dodirom. Kada je Istraživanje dodirom uključeno, možete da čujete ili vidite opise stavke na koju ste stavili prst ili da komunicirate sa tabletom pomoću pokreta."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> želi da omogući Istraživanje dodirom. Kada je Istraživanje dodirom uključeno, možete da čujete ili vidite opise stavke na koju ste stavili prst ili da komunicirate sa telefonom pomoću pokreta."</string>
+ <string name="oneMonthDurationPast" msgid="7396384508953779925">"Pre mesec dana"</string>
+ <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Pre mesec dana"</string>
+ <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
+ <item quantity="one">Prethodni <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
+ <item quantity="few">Prethodna <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+ <item quantity="other">Prethodnih <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
+ </plurals>
+ <string name="last_month" msgid="3959346739979055432">"Prošlog meseca"</string>
+ <string name="older" msgid="5211975022815554840">"Starije"</string>
+ <string name="preposition_for_date" msgid="9093949757757445117">"<xliff:g id="DATE">%s</xliff:g>"</string>
+ <string name="preposition_for_time" msgid="5506831244263083793">"u <xliff:g id="TIME">%s</xliff:g>"</string>
+ <string name="preposition_for_year" msgid="5040395640711867177">"u <xliff:g id="YEAR">%s</xliff:g>."</string>
+ <string name="day" msgid="8144195776058119424">"dan"</string>
+ <string name="days" msgid="4774547661021344602">"dana"</string>
+ <string name="hour" msgid="2126771916426189481">"sat"</string>
+ <string name="hours" msgid="894424005266852993">"sata"</string>
+ <string name="minute" msgid="9148878657703769868">"min"</string>
+ <string name="minutes" msgid="5646001005827034509">"min"</string>
+ <string name="second" msgid="3184235808021478">"sek"</string>
+ <string name="seconds" msgid="3161515347216589235">"sek"</string>
+ <string name="week" msgid="5617961537173061583">"nedelja"</string>
+ <string name="weeks" msgid="6509623834583944518">"nedelje(a)"</string>
+ <string name="year" msgid="4001118221013892076">"godina"</string>
+ <string name="years" msgid="6881577717993213522">"godine(a)"</string>
+ <plurals name="duration_seconds" formatted="false" msgid="4527986939729687805">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sekunda</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+ </plurals>
+ <plurals name="duration_minutes" formatted="false" msgid="643786953939956125">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> minut</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> minuta</item>
+ </plurals>
+ <plurals name="duration_hours" formatted="false" msgid="6826233369186668274">
+ <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> sat</item>
+ <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sata</item>
+ <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sati</item>
+ </plurals>
+ <string name="VideoView_error_title" msgid="3534509135438353077">"Problem sa video snimkom"</string>
+ <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ovaj video ne može da se strimuje na ovom uređaju."</string>
+ <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ne možete da pustite ovaj video."</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"Potvrdi"</string>
+ <string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
+ <string name="noon" msgid="7245353528818587908">"podne"</string>
+ <string name="Noon" msgid="3342127745230013127">"Podne"</string>
+ <string name="midnight" msgid="7166259508850457595">"ponoć"</string>
+ <string name="Midnight" msgid="5630806906897892201">"Ponoć"</string>
+ <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
+ <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
+ <string name="selectAll" msgid="6876518925844129331">"Izaberi sve"</string>
+ <string name="cut" msgid="3092569408438626261">"Iseci"</string>
+ <string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
+ <string name="paste" msgid="5629880836805036433">"Nalepi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Nalepi kao običan tekst"</string>
+ <string name="replace" msgid="5781686059063148930">"Zameni..."</string>
+ <string name="delete" msgid="6098684844021697789">"Izbriši"</string>
+ <string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL adresu"</string>
+ <string name="selectTextMode" msgid="1018691815143165326">"Izaberi tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Opozovi"</string>
+ <string name="redo" msgid="7759464876566803888">"Ponovi"</string>
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"Izbor teksta"</string>
+ <string name="addToDictionary" msgid="4352161534510057874">"Dodaj u rečnik"</string>
+ <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
+ <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
+ <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za skladištenje je na izmaku"</string>
+ <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno skladišnog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
+ <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
+ <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
+ <string name="ok" msgid="5970060430562524910">"Potvrdi"</string>
+ <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+ <string name="yes" msgid="5362982303337969312">"Potvrdi"</string>
+ <string name="no" msgid="5141531044935541497">"Otkaži"</string>
+ <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
+ <string name="loading" msgid="7933681260296021180">"Učitava se…"</string>
+ <string name="capital_on" msgid="1544682755514494298">"DA"</string>
+ <string name="capital_off" msgid="6815870386972805832">"NE"</string>
+ <string name="whichApplication" msgid="4533185947064773386">"Dovršavanje radnje pomoću"</string>
+ <string name="whichApplicationNamed" msgid="8260158865936942783">"Završite radnju pomoću aplikacije %1$s"</string>
+ <string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
+ <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
+ <string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
+ <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
+ <string name="whichSendApplication" msgid="6902512414057341668">"Delite pomoću"</string>
+ <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Delite pomoću aplikacije %1$s"</string>
+ <string name="whichHomeApplication" msgid="4307587691506919691">"Izaberite aplikaciju za početnu stranicu"</string>
+ <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Koristite %1$s za početnu"</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"Podrazumevano koristi za ovu radnju."</string>
+ <string name="use_a_different_app" msgid="8134926230585710243">"Koristite drugu aplikaciju"</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Obrišite podrazumevano podešavanje u meniju Podešavanja sistema > Aplikacije > Preuzeto."</string>
+ <string name="chooseActivity" msgid="7486876147751803333">"Izaberite radnju"</string>
+ <string name="chooseUsbActivity" msgid="6894748416073583509">"Izbor aplikacije za USB uređaj"</string>
+ <string name="noApplications" msgid="2991814273936504689">"Nijedna aplikacija ne može da obavlja ovu radnju."</string>
+ <string name="aerr_title" msgid="1905800560317137752"></string>
+ <string name="aerr_application" msgid="932628488013092776">"Nažalost, aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> je prestala s radom."</string>
+ <string name="aerr_process" msgid="4507058997035697579">"Nažalost, proces <xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen."</string>
+ <string name="aerr_process_silence" msgid="4226685530196000222">"Nečujna otkazivanja od procesa <xliff:g id="PROCESS">%1$s</xliff:g> do restartovanja."</string>
+ <string name="anr_title" msgid="4351948481459135709"></string>
+ <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g> ne reaguje.\n\nDa li želite da je zatvorite?"</string>
+ <string name="anr_activity_process" msgid="5776209883299089767">"Aktivnost <xliff:g id="ACTIVITY">%1$s</xliff:g> ne reaguje.\n\nDa li želite da je zatvorite?"</string>
+ <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne reaguje. Da li želite da je zatvorite?"</string>
+ <string name="anr_process" msgid="6513209874880517125">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> ne raeguje.\n\nDa li želite da ga zatvorite?"</string>
+ <string name="force_close" msgid="8346072094521265605">"Potvrdi"</string>
+ <string name="report" msgid="4060218260984795706">"Prijavi"</string>
+ <string name="wait" msgid="7147118217226317732">"Sačekaj"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Stranica je prestala da se odaziva.\n\n Da li želite da je zatvorite?"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"Aplikacija je preusmerena"</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je sada pokrenuta."</string>
+ <string name="launch_warning_original" msgid="188102023021668683">"Prvobitno je pokrenuta aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Razmera"</string>
+ <string name="screen_compat_mode_show" msgid="4013878876486655892">"Uvek prikazuj"</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Ponovo omogućite u meniju Sistemska podešavanja > Aplikacije > Preuzeto."</string>
+ <string name="smv_application" msgid="3307209192155442829">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) je prekršila samonametnute StrictMode smernice."</string>
+ <string name="smv_process" msgid="5120397012047462446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> je prekršio samonametnute StrictMode smernice."</string>
+ <string name="android_upgrading_title" msgid="1584192285441405746">"Android se nadograđuje…"</string>
+ <string name="android_start_title" msgid="8418054686415318207">"Android se pokreće…"</string>
+ <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Memorija se optimizuje."</string>
+ <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizovanje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
+ <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
+ <string name="android_upgrading_complete" msgid="1405954754112999229">"Završavanje pokretanja."</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string>
+ <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Dodirnite da biste prešli na aplikaciju"</string>
+ <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite li da pređete na drugu aplikaciju?"</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta druga aplikacija koja mora da bude zaustavljena da biste mogli da pokrenete novu."</string>
+ <string name="old_app_action" msgid="493129172238566282">"Vrati se u <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="old_app_description" msgid="2082094275580358049">"Ne pokrećite novu aplikaciju."</string>
+ <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
+ <string name="new_app_description" msgid="1932143598371537340">"Zaustavlja staru aplikaciju bez čuvanja."</string>
+ <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
+ <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Snimak dinamičkog dela memorije je napravljen; dodirnite za deljenje"</string>
+ <string name="dump_heap_title" msgid="5864292264307651673">"Želite li da delite snimak dinamičkog dela memorije?"</string>
+ <string name="dump_heap_text" msgid="4809417337240334941">"Proces <xliff:g id="PROC">%1$s</xliff:g> je premašio ograničenje memorije za proces od <xliff:g id="SIZE">%2$s</xliff:g>. Snimak dinamičkog dela memorije je dostupan i možete da ga delite sa programerom. Budite oprezni: ovaj snimak dinamičkog dela memorije može da sadrži neke lične podatke kojima aplikacija može da pristupa."</string>
+ <string name="sendText" msgid="5209874571959469142">"Izaberite radnju za tekst"</string>
+ <string name="volume_ringtone" msgid="6885421406845734650">"Jačina zvuka zvona"</string>
+ <string name="volume_music" msgid="5421651157138628171">"Jačina zvuka medija"</string>
+ <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Igranje preko Bluetooth-a"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Podešen je nečujni zvuk zvona"</string>
+ <string name="volume_call" msgid="3941680041282788711">"Jačina zvuka dolaznog poziva"</string>
+ <string name="volume_bluetooth_call" msgid="2002891926351151534">"Jačina zvuka dolazećeg poziva preko Bluetooth-a"</string>
+ <string name="volume_alarm" msgid="1985191616042689100">"Jačina zvuka alarma"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"Jačina zvuka za obaveštenja"</string>
+ <string name="volume_unknown" msgid="1400219669770445902">"Jačina zvuka"</string>
+ <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Jačina zvuka Bluetooth uređaja"</string>
+ <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Jačina melodije zvona"</string>
+ <string name="volume_icon_description_incall" msgid="8890073218154543397">"Jačina zvuka poziva"</string>
+ <string name="volume_icon_description_media" msgid="4217311719665194215">"Jačina zvuka medija"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka obaveštenja"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"Podrazumevani zvuk zvona"</string>
+ <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Podrazumevani zvuk zvona (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
+ <string name="ringtone_picker_title" msgid="3515143939175119094">"Zvukovi zvona"</string>
+ <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznati zvuk zvona"</string>
+ <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
+ <item quantity="one">Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
+ <item quantity="one">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
+ <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
+ </plurals>
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
+ <string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
+ <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
+ <skip />
+ <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
+ <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Dodirnite za opcije"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
+ <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
+ <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
+ <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi da se poveže na Wi-Fi mrežu %2$s"</string>
+ <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokrenite Wi-Fi Direct. Time ćete isključiti klijenta/hotspot za Wi-Fi."</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nije moguće pokrenuti Wi-Fi Direct."</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je uključen"</string>
+ <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za podešavanja"</string>
+ <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
+ <string name="decline" msgid="2112225451706137894">"Odbij"</string>
+ <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslata"</string>
+ <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozivnica za povezivanje"</string>
+ <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
+ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kome:"</string>
+ <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Unesite potrebni PIN:"</string>
+ <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će privremeno prekinuti vezu sa Wi-Fi-jem dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"TV će privremeno prekinuti vezu sa Wi-Fi-jem dok je povezan na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će privremeno prekinuti vezu sa Wi-Fi-jem dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="select_character" msgid="3365550120617701745">"Umetanje znaka"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
+ <string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> šalje veliki broj SMS poruka. Želite li da dozvolite ovoj aplikaciji da nastavi sa slanjem poruka?"</string>
+ <string name="sms_control_yes" msgid="3663725993855816807">"Dozvoli"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Odbij"</string>
+ <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> želi da pošalje poruku na adresu <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string>
+ <string name="sms_short_code_details" msgid="5873295990846059400">"Ovo "<b>"može da prouzrokuje troškove"</b>" na računu za mobilni uređaj."</string>
+ <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Ovo će prouzrokovati troškove na računu za mobilni uređaj."</b></string>
+ <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Pošalji"</string>
+ <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Otkaži"</string>
+ <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Zapamti moj izbor"</string>
+ <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Ovo možete da promenite kasnije u Podešavanja > Aplikacije"</string>
+ <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Uvek dozvoli"</string>
+ <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Nikada ne dozvoli"</string>
+ <string name="sim_removed_title" msgid="6227712319223226185">"SIM kartica je uklonjena"</string>
+ <string name="sim_removed_message" msgid="5450336489923274918">"Mobilna mreža neće biti dostupna dok ne pokrenete uređaj ponovo uz umetanje važeće SIM kartice."</string>
+ <string name="sim_done_button" msgid="827949989369963775">"Gotovo"</string>
+ <string name="sim_added_title" msgid="3719670512889674693">"SIM kartica je dodata"</string>
+ <string name="sim_added_message" msgid="7797975656153714319">"Ponovo pokrenite uređaj da biste pristupili mobilnoj mreži."</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"Ponovo pokreni"</string>
+ <string name="time_picker_dialog_title" msgid="8349362623068819295">"Podešavanje vremena"</string>
+ <string name="date_picker_dialog_title" msgid="5879450659453782278">"Podešavanje datuma"</string>
+ <string name="date_time_set" msgid="5777075614321087758">"Podesi"</string>
+ <string name="date_time_done" msgid="2507683751759308828">"Gotovo"</string>
+ <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"NOVO: "</font></string>
+ <string name="perms_description_app" msgid="5139836143293299417">"Omogućava <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
+ <string name="no_permissions" msgid="7283357728219338112">"Nije potrebna nijedna dozvola"</string>
+ <string name="perm_costs_money" msgid="4902470324142151116">"ovo će vam možda biti naplaćeno"</string>
+ <string name="dlg_ok" msgid="7376953167039865701">"Potvrdi"</string>
+ <string name="usb_charging_notification_title" msgid="4004114449249406402">"USB za punjenje"</string>
+ <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB za prenos datoteka"</string>
+ <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos slika"</string>
+ <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
+ <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Povezano sa USB dodatkom"</string>
+ <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za još opcija."</string>
+ <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
+ <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
+ <string name="select_input_method" msgid="8547250819326693584">"Promenite tastaturu"</string>
+ <string name="configure_input_methods" msgid="4769971288371946846">"Izaberite tastature"</string>
+ <string name="show_ime" msgid="9157568568695230830">"Prikazivanje metoda unosa"</string>
+ <string name="hardware" msgid="7517821086888990278">"Hardver"</string>
+ <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Izbor rasporeda tastature"</string>
+ <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"Dodirnite da biste izabrali raspored tastature."</string>
+ <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
+ <string name="candidates_style" msgid="4333913089637062257"><u>"kandidati"</u></string>
+ <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> se priprema"</string>
+ <string name="ext_media_checking_notification_message" msgid="4747432538578886744">"Proverava se da li postoje greške"</string>
+ <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
+ <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Za prenos slika i medija"</string>
+ <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen"</string>
+ <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da biste ga popravili."</string>
+ <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"Uređaj <xliff:g id="NAME">%s</xliff:g> nije podržan"</string>
+ <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Ovaj uređaj ne podržava uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da biste podesili podržani format."</string>
+ <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Uređaj <xliff:g id="NAME">%s</xliff:g> je neočekivano uklonjen"</string>
+ <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Isključite uređaj <xliff:g id="NAME">%s</xliff:g> pre uklanjanja da ne biste izgubili podatke"</string>
+ <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen"</string>
+ <string name="ext_media_nomedia_notification_message" msgid="6471542972147056586">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen; umetnite novi"</string>
+ <string name="ext_media_unmounting_notification_title" msgid="640674168454809372">"<xliff:g id="NAME">%s</xliff:g> se još uvek izbacuje…"</string>
+ <string name="ext_media_unmounting_notification_message" msgid="4182843895023357756">"Ne uklanjajte"</string>
+ <string name="ext_media_init_action" msgid="7952885510091978278">"Podesi"</string>
+ <string name="ext_media_unmount_action" msgid="1121883233103278199">"Izbaci"</string>
+ <string name="ext_media_browse_action" msgid="8322172381028546087">"Istraži"</string>
+ <string name="ext_media_missing_title" msgid="620980315821543904">"<xliff:g id="NAME">%s</xliff:g> nedostaje"</string>
+ <string name="ext_media_missing_message" msgid="5761133583368750174">"Umetnite uređaj ponovo"</string>
+ <string name="ext_media_move_specific_title" msgid="1471100343872375842">"Prenosi se <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_move_title" msgid="1022809140035962662">"Podaci se prenose"</string>
+ <string name="ext_media_move_success_title" msgid="8575300932957954671">"Prenos je završen"</string>
+ <string name="ext_media_move_success_message" msgid="4199002148206265426">"Podaci su preneseni na uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="ext_media_move_failure_title" msgid="7613189040358789908">"Prenos podataka nije uspeo"</string>
+ <string name="ext_media_move_failure_message" msgid="1978096440816403360">"Podaci su ostali na originalnoj lokaciji"</string>
+ <string name="ext_media_status_removed" msgid="6576172423185918739">"Uklonjen je"</string>
+ <string name="ext_media_status_unmounted" msgid="2551560878416417752">"Izbačen je"</string>
+ <string name="ext_media_status_checking" msgid="6193921557423194949">"Proverava se..."</string>
+ <string name="ext_media_status_mounted" msgid="7253821726503179202">"Spreman je"</string>
+ <string name="ext_media_status_mounted_ro" msgid="8020978752406021015">"Samo za čitanje"</string>
+ <string name="ext_media_status_bad_removal" msgid="8395398567890329422">"Uklonjen je na nebezbedan način"</string>
+ <string name="ext_media_status_unmountable" msgid="805594039236667894">"Oštećen je"</string>
+ <string name="ext_media_status_unsupported" msgid="4691436711745681828">"Nije podržan"</string>
+ <string name="ext_media_status_ejecting" msgid="5463887263101234174">"Izbacuje se..."</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"Formatira se..."</string>
+ <string name="ext_media_status_missing" msgid="5638633895221670766">"Nije umetnut"</string>
+ <string name="activity_list_empty" msgid="1675388330786841066">"Nije pronađena nijedna podudarna aktivnost."</string>
+ <string name="permlab_route_media_output" msgid="6243022988998972085">"usmeravanje izlaza medija"</string>
+ <string name="permdesc_route_media_output" msgid="4932818749547244346">"Dozvoljava aplikaciji da usmerava izlaz medija na druge spoljne uređaje."</string>
+ <string name="permlab_readInstallSessions" msgid="3713753067455750349">"čitanje sesija instaliranja"</string>
+ <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instaliranja. To joj dozvoljava da vidi detalje o aktivnim instalacijama paketa."</string>
+ <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketa za instaliranje"</string>
+ <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava da aplikacija zahteva instalaciju paketa."</string>
+ <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput da biste kontrolisali zum"</string>
+ <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nije moguće dodati vidžet."</string>
+ <string name="ime_action_go" msgid="8320845651737369027">"Idi"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"Pretraži"</string>
+ <string name="ime_action_send" msgid="2316166556349314424">"Pošalji"</string>
+ <string name="ime_action_next" msgid="3138843904009813834">"Sledeće"</string>
+ <string name="ime_action_done" msgid="8971516117910934605">"Gotovo"</string>
+ <string name="ime_action_previous" msgid="1443550039250105948">"Prethodno"</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"Izvrši"</string>
+ <string name="dial_number_using" msgid="5789176425167573586">"Biraj broj\nkoristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="create_contact_using" msgid="4947405226788104538">"Kreirajte kontakt\nkoristeći <xliff:g id="NUMBER">%s</xliff:g>"</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Sledeće aplikacije zahtevaju dozvolu za pristup nalogu, kako sada, tako i ubuduće."</string>
+ <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Želite da odobrite ovaj zahtev?"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"Zahtev za pristup"</string>
+ <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
+ <string name="deny" msgid="2081879885755434506">"Odbij"</string>
+ <string name="permission_request_notification_title" msgid="6486759795926237907">"Zatražena je dozvola"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Zatražena je dozvola\nza nalog <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+ <string name="forward_intent_to_owner" msgid="1207197447013960896">"Koristite ovu aplikaciju izvan poslovnog profila"</string>
+ <string name="forward_intent_to_work" msgid="621480743856004612">"Koristite ovu aplikaciju na poslovnom profilu"</string>
+ <string name="input_method_binding_label" msgid="1283557179944992649">"Metod unosa"</string>
+ <string name="sync_binding_label" msgid="3687969138375092423">"Sinhronizacija"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"Pristupačnost"</string>
+ <string name="wallpaper_binding_label" msgid="1240087844304687662">"Pozadina"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"Promena pozadine"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"Monitor obaveštenja"</string>
+ <string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dobavljač uslova"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obaveštenja"</string>
+ <string name="vpn_title" msgid="19615213552042827">"VPN je aktiviran"</string>
+ <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
+ <string name="vpn_text" msgid="3011306607126450322">"Dodirnite da biste upravljali mrežom."</string>
+ <string name="vpn_text_long" msgid="6407351006249174473">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
+ <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string>
+ <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string>
+ <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string>
+ <string name="vpn_lockdown_config" msgid="6415899150671537970">"Dodirnite da biste konfigurisali"</string>
+ <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
+ <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
+ <string name="submit" msgid="1602335572089911941">"Pošalji"</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Režim rada u automobilu je omogućen"</string>
+ <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Dodirnite da biste izašli iz režima rada u automobilu."</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
+ <string name="tethered_notification_message" msgid="6857031760103062982">"Dodirnite da biste podesili."</string>
+ <string name="back_button_label" msgid="2300470004503343439">"Nazad"</string>
+ <string name="next_button_label" msgid="1080555104677992408">"Next"</string>
+ <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
+ <string name="no_matches" msgid="8129421908915840737">"Nema podudaranja"</string>
+ <string name="find_on_page" msgid="1946799233822820384">"Pronađi na stranici"</string>
+ <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
+ <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ <item quantity="few"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> od <xliff:g id="TOTAL">%d</xliff:g></item>
+ </plurals>
+ <string name="action_mode_done" msgid="7217581640461922289">"Gotovo"</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Brisanje USB memorije..."</string>
+ <string name="progress_erasing" product="default" msgid="6596988875507043042">"Brisanje SD kartice..."</string>
+ <string name="share" msgid="1778686618230011964">"Deli"</string>
+ <string name="find" msgid="4808270900322985960">"Pronađi"</string>
+ <string name="websearch" msgid="4337157977400211589">"Veb-pretraga"</string>
+ <string name="find_next" msgid="5742124618942193978">"Pronađi sledeće"</string>
+ <string name="find_previous" msgid="2196723669388360506">"Pronađi prethodno"</string>
+ <string name="gpsNotifTicker" msgid="5622683912616496172">"Zahtev za lokaciju od korisnika <xliff:g id="NAME">%s</xliff:g>"</string>
+ <string name="gpsNotifTitle" msgid="5446858717157416839">"Zahtev za lokaciju"</string>
+ <string name="gpsNotifMessage" msgid="1374718023224000702">"Zahteva <xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>)"</string>
+ <string name="gpsVerifYes" msgid="2346566072867213563">"Da"</string>
+ <string name="gpsVerifNo" msgid="1146564937346454865">"Ne"</string>
+ <string name="sync_too_many_deletes" msgid="5296321850662746890">"Premašeno je ograničenje za brisanje"</string>
+ <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"Postoje izbrisane stavke (<xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>) za <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, nalog <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Šta želite da uradite?"</string>
+ <string name="sync_really_delete" msgid="2572600103122596243">"Izbriši stavke"</string>
+ <string name="sync_undo_deletes" msgid="2941317360600338602">"Opozovi brisanja"</string>
+ <string name="sync_do_nothing" msgid="3743764740430821845">"Ne radi ništa za sada"</string>
+ <string name="choose_account_label" msgid="5655203089746423927">"Izbor naloga"</string>
+ <string name="add_account_label" msgid="2935267344849993553">"Dodaj nalog"</string>
+ <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj nalog"</string>
+ <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećavanje"</string>
+ <string name="number_picker_decrement_button" msgid="476050778386779067">"Smanjivanje"</string>
+ <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> dodirnite i zadržite."</string>
+ <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Prevucite nagore da biste povećali, a nadole da biste smanjili."</string>
+ <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Povećavanje minuta"</string>
+ <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Smanjivanje minuta"</string>
+ <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Povećavanje sati"</string>
+ <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Smanjivanje sati"</string>
+ <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Podesi po podne"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Podesi pre podne"</string>
+ <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Povećavanje meseca"</string>
+ <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Smanjivanje meseca"</string>
+ <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Povećavanje dana"</string>
+ <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanjivanje dana"</string>
+ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećavanje godine"</string>
+ <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanjivanje godine"</string>
+ <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prethodni mesec"</string>
+ <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sledeći mesec"</string>
+ <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
+ <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Otkaži"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
+ <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotovo"</string>
+ <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Promena režima"</string>
+ <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Izaberite aplikaciju"</string>
+ <string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"Nije moguće pokrenuti <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="shareactionprovider_share_with" msgid="806688056141131819">"Deli sa"</string>
+ <string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Deli sa aplikacijom <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+ <string name="content_description_sliding_handle" msgid="415975056159262248">"Klizna ručica. Dodirnite i zadržite."</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Prevucite da biste otključali."</string>
+ <string name="keyboard_headset_required_to_hear_password" msgid="7011927352267668657">"Priključite slušalice da biste čuli izgovorene tastere za lozinku."</string>
+ <string name="keyboard_password_character_no_headset" msgid="2859873770886153678">"Tačka."</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"Kretanje do Početne"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"Kretanje nagore"</string>
+ <string name="action_menu_overflow_description" msgid="2295659037509008453">"Još opcija"</string>
+ <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
+ <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
+ <string name="storage_internal" msgid="4891916833657929263">"Interna memorija"</string>
+ <string name="storage_sd_card" msgid="3282948861378286745">"SD kartica"</string>
+ <string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD kartica"</string>
+ <string name="storage_usb_drive" msgid="6261899683292244209">"USB disk"</string>
+ <string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
+ <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
+ <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
+ <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string>
+ <string name="data_usage_warning_body" msgid="2814673551471969954">"Dodirnite za pregled kor. i pod."</string>
+ <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
+ <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
+ <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Nema više podataka za mobilne"</string>
+ <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Nema više Wi-Fi podataka"</string>
+ <string name="data_usage_limit_body" msgid="291731708279614081">"Potrošili ste podatke za ovaj mesec"</string>
+ <string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"Prekoračen prenos 2G-3G podataka"</string>
+ <string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"Prekoračenje prenosa 4G podataka"</string>
+ <string name="data_usage_mobile_limit_snoozed_title" msgid="4941346653729943789">"Ograničenje mobilnih podataka je prekoračeno"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Prekoračenje prenosa Wi-Fi podat."</string>
+ <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> preko navedenog ograničenja."</string>
+ <string name="data_usage_restricted_title" msgid="5965157361036321914">"Pozadinski podaci su ograničeni"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Dodirnite da biste uklonili ograničenje."</string>
+ <string name="ssl_certificate" msgid="6510040486049237639">"Bezbednosni sertifikat"</string>
+ <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Ovaj sertifikat je važeći."</string>
+ <string name="issued_to" msgid="454239480274921032">"Izdato za:"</string>
+ <string name="common_name" msgid="2233209299434172646">"Uobičajeni naziv:"</string>
+ <string name="org_name" msgid="6973561190762085236">"Organizacija:"</string>
+ <string name="org_unit" msgid="7265981890422070383">"Organizaciona jedinica:"</string>
+ <string name="issued_by" msgid="2647584988057481566">"Izdao/la:"</string>
+ <string name="validity_period" msgid="8818886137545983110">"Važnost:"</string>
+ <string name="issued_on" msgid="5895017404361397232">"Izdato:"</string>
+ <string name="expires_on" msgid="3676242949915959821">"Ističe:"</string>
+ <string name="serial_number" msgid="758814067660862493">"Serijski broj:"</string>
+ <string name="fingerprints" msgid="4516019619850763049">"Digitalni otisci:"</string>
+ <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 digitalni otisak:"</string>
+ <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 digitalni otisak:"</string>
+ <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"Prikaži sve"</string>
+ <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"Izbor aktivnosti"</string>
+ <string name="share_action_provider_share_with" msgid="5247684435979149216">"Deli sa"</string>
+ <string name="sending" msgid="3245653681008218030">"Slanje..."</string>
+ <string name="launchBrowserDefault" msgid="2057951947297614725">"Želite li da pokrenete pregledač?"</string>
+ <string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
+ <string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
+ <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
+ <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tablet"</string>
+ <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
+ <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
+ <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Slušalice"</string>
+ <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Zvučnici bazne stanice"</string>
+ <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
+ <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
+ <string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"Bluetooth audio"</string>
+ <string name="wireless_display_route_description" msgid="9070346425023979651">"Bežični ekran"</string>
+ <string name="media_route_button_content_description" msgid="591703006349356016">"Prebacuj"</string>
+ <string name="media_route_chooser_title" msgid="1751618554539087622">"Povežite sa uređajem"</string>
+ <string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Prebacite ekran na uređaj"</string>
+ <string name="media_route_chooser_searching" msgid="4776236202610828706">"Traženje uređaja…"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Podešavanja"</string>
+ <string name="media_route_controller_disconnect" msgid="8966120286374158649">"Prekini vezu"</string>
+ <string name="media_route_status_scanning" msgid="7279908761758293783">"Skeniranje..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"Povezuje se..."</string>
+ <string name="media_route_status_available" msgid="6983258067194649391">"Dostupna"</string>
+ <string name="media_route_status_not_available" msgid="6739899962681886401">"Nisu dostupne"</string>
+ <string name="media_route_status_in_use" msgid="4533786031090198063">"U upotrebi"</string>
+ <string name="display_manager_built_in_display_name" msgid="2583134294292563941">"Ugrađeni ekran"</string>
+ <string name="display_manager_hdmi_display_name" msgid="1555264559227470109">"HDMI ekran"</string>
+ <string name="display_manager_overlay_display_name" msgid="5142365982271620716">"Postavljeni element br. <xliff:g id="ID">%1$d</xliff:g>"</string>
+ <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>×<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string>
+ <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", bezbedno"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravljeni šablon"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite lozinku"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM kartica je sada onemogućena. Unesite PUK kôd da biste nastavili. Za detalje kontaktirajte operatera."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Unesite željeni PIN kôd"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrdite željeni PIN kôd"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+ <string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"PIN kôd je netačan."</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="6025069204539532000">"PUK kôd treba da ima 8 brojeva."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravni PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi se ne podudaraju"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja unosa šablona"</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Da biste otključali, prijavite se pomoću Google naloga."</string>
+ <string name="kg_login_username_hint" msgid="5718534272070920364">"Korisničko ime (imejl adresa)"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"Lozinka"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Prijavi me"</string>
+ <string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili lozinka."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili lozinku?\nPosetite adresu "<b>"google.com/accounts/recovery"</b>"."</string>
+ <string name="kg_login_checking_password" msgid="1052685197710252395">"Provera naloga…"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni 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> sekunde(i)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu 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> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
+ <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
+ <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
+ <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Držite sa dva prsta da biste omogućili pristupačnost."</string>
+ <string name="accessibility_enabled" msgid="1381972048564547685">"Pristupačnost je omogućena."</string>
+ <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost je otkazana."</string>
+ <string name="user_switched" msgid="3768006783166984410">"Aktuelni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
+ <string name="user_switching_message" msgid="2871009331809089783">"Prebacivanje na <xliff:g id="NAME">%1$s</xliff:g>…"</string>
+ <string name="user_logging_out_message" msgid="8939524935808875155">"Odjavljuje se <xliff:g id="NAME">%1$s</xliff:g>…"</string>
+ <string name="owner_name" msgid="2716755460376028154">"Vlasnik"</string>
+ <string name="error_message_title" msgid="4510373083082500195">"Greška"</string>
+ <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Administrator nije dozvolio ovu promenu"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Nije pronađena nijedna aplikacija koja bi mogla da obavi ovu radnju"</string>
+ <string name="revoke" msgid="5404479185228271586">"Opozovi"</string>
+ <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
+ <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
+ <string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
+ <string name="mediasize_iso_a3" msgid="3023213259314236123">"ISO A3"</string>
+ <string name="mediasize_iso_a4" msgid="231745325296873764">"ISO A4"</string>
+ <string name="mediasize_iso_a5" msgid="3484327407340865411">"ISO A5"</string>
+ <string name="mediasize_iso_a6" msgid="4861908487129577530">"ISO A6"</string>
+ <string name="mediasize_iso_a7" msgid="5890208588072936130">"ISO A7"</string>
+ <string name="mediasize_iso_a8" msgid="4319425041085816612">"ISO A8"</string>
+ <string name="mediasize_iso_a9" msgid="4882220529506432008">"ISO A9"</string>
+ <string name="mediasize_iso_a10" msgid="2382866026365359391">"ISO A10"</string>
+ <string name="mediasize_iso_b0" msgid="3651827147402009675">"ISO B0"</string>
+ <string name="mediasize_iso_b1" msgid="6072859628278739957">"ISO B1"</string>
+ <string name="mediasize_iso_b2" msgid="1348731852150380378">"ISO B2"</string>
+ <string name="mediasize_iso_b3" msgid="2612510181259261379">"ISO B3"</string>
+ <string name="mediasize_iso_b4" msgid="695151378838115434">"ISO B4"</string>
+ <string name="mediasize_iso_b5" msgid="4863754285582212487">"ISO B5"</string>
+ <string name="mediasize_iso_b6" msgid="5305816292139647241">"ISO B6"</string>
+ <string name="mediasize_iso_b7" msgid="531673542602786624">"ISO B7"</string>
+ <string name="mediasize_iso_b8" msgid="9164474595708850034">"ISO B8"</string>
+ <string name="mediasize_iso_b9" msgid="282102976764774160">"ISO B9"</string>
+ <string name="mediasize_iso_b10" msgid="4517141714407898976">"ISO B10"</string>
+ <string name="mediasize_iso_c0" msgid="3103521357901591100">"ISO C0"</string>
+ <string name="mediasize_iso_c1" msgid="1231954105985048595">"ISO C1"</string>
+ <string name="mediasize_iso_c2" msgid="927702816980087462">"ISO C2"</string>
+ <string name="mediasize_iso_c3" msgid="835154173518304159">"ISO C3"</string>
+ <string name="mediasize_iso_c4" msgid="5095951985108194011">"ISO C4"</string>
+ <string name="mediasize_iso_c5" msgid="1985397450332305739">"ISO C5"</string>
+ <string name="mediasize_iso_c6" msgid="8147421924174693013">"ISO C6"</string>
+ <string name="mediasize_iso_c7" msgid="8993994925276122950">"ISO C7"</string>
+ <string name="mediasize_iso_c8" msgid="6871178104139598957">"ISO C8"</string>
+ <string name="mediasize_iso_c9" msgid="7983532635227561362">"ISO C9"</string>
+ <string name="mediasize_iso_c10" msgid="5040764293406765584">"ISO C10"</string>
+ <string name="mediasize_na_letter" msgid="2841414839888344296">"Letter"</string>
+ <string name="mediasize_na_gvrnmt_letter" msgid="5295836838862962809">"Government Letter"</string>
+ <string name="mediasize_na_legal" msgid="8621364037680465666">"Legal"</string>
+ <string name="mediasize_na_junior_legal" msgid="3309324162155085904">"Junior Legal"</string>
+ <string name="mediasize_na_ledger" msgid="5567030340509075333">"Ledger"</string>
+ <string name="mediasize_na_tabloid" msgid="4571735038501661757">"Tabloid"</string>
+ <string name="mediasize_na_index_3x5" msgid="5182901917818625126">"Index Card 3x5"</string>
+ <string name="mediasize_na_index_4x6" msgid="7687620625422312396">"Index Card 4x6"</string>
+ <string name="mediasize_na_index_5x8" msgid="8834215284646872800">"Index Card 5x8"</string>
+ <string name="mediasize_na_monarch" msgid="213639906956550754">"Monarch"</string>
+ <string name="mediasize_na_quarto" msgid="835778493593023223">"Quarto"</string>
+ <string name="mediasize_na_foolscap" msgid="1573911237983677138">"Foolscap"</string>
+ <string name="mediasize_chinese_roc_8k" msgid="3626855847189438896">"ROC 8K"</string>
+ <string name="mediasize_chinese_roc_16k" msgid="9182191577022943355">"ROC 16K"</string>
+ <string name="mediasize_chinese_prc_1" msgid="4793232644980170500">"PRC 1"</string>
+ <string name="mediasize_chinese_prc_2" msgid="5404109730975720670">"PRC 2"</string>
+ <string name="mediasize_chinese_prc_3" msgid="1335092253339363526">"PRC 3"</string>
+ <string name="mediasize_chinese_prc_4" msgid="9167997800486569834">"PRC 4"</string>
+ <string name="mediasize_chinese_prc_5" msgid="845875168823541497">"PRC 5"</string>
+ <string name="mediasize_chinese_prc_6" msgid="3220325667692648789">"PRC 6"</string>
+ <string name="mediasize_chinese_prc_7" msgid="1776792138507038527">"PRC 7"</string>
+ <string name="mediasize_chinese_prc_8" msgid="1417176642687456692">"PRC 8"</string>
+ <string name="mediasize_chinese_prc_9" msgid="4785983473123798365">"PRC 9"</string>
+ <string name="mediasize_chinese_prc_10" msgid="7847982299391851899">"PRC 10"</string>
+ <string name="mediasize_chinese_prc_16k" msgid="262793383539980677">"PRC 16K"</string>
+ <string name="mediasize_chinese_om_pa_kai" msgid="5256815579447959814">"Pa Kai"</string>
+ <string name="mediasize_chinese_om_dai_pa_kai" msgid="7336412963441354407">"Dai Pa Kai"</string>
+ <string name="mediasize_chinese_om_jurro_ku_kai" msgid="6324465444100490742">"Jurro Ku Kai"</string>
+ <string name="mediasize_japanese_jis_b10" msgid="1787262845627694376">"JIS B10"</string>
+ <string name="mediasize_japanese_jis_b9" msgid="3336035783663287470">"JIS B9"</string>
+ <string name="mediasize_japanese_jis_b8" msgid="6195398299104345731">"JIS B8"</string>
+ <string name="mediasize_japanese_jis_b7" msgid="1674621886902828884">"JIS B7"</string>
+ <string name="mediasize_japanese_jis_b6" msgid="4170576286062657435">"JIS B6"</string>
+ <string name="mediasize_japanese_jis_b5" msgid="4899297958100032533">"JIS B5"</string>
+ <string name="mediasize_japanese_jis_b4" msgid="4213158129126666847">"JIS B4"</string>
+ <string name="mediasize_japanese_jis_b3" msgid="8513715307410310696">"JIS B3"</string>
+ <string name="mediasize_japanese_jis_b2" msgid="4777690211897131190">"JIS B2"</string>
+ <string name="mediasize_japanese_jis_b1" msgid="4608142385457034603">"JIS B1"</string>
+ <string name="mediasize_japanese_jis_b0" msgid="7587108366572243991">"JIS B0"</string>
+ <string name="mediasize_japanese_jis_exec" msgid="5244075432263649068">"JIS Exec"</string>
+ <string name="mediasize_japanese_chou4" msgid="4941652015032631361">"Chou4"</string>
+ <string name="mediasize_japanese_chou3" msgid="6387319169263957010">"Chou3"</string>
+ <string name="mediasize_japanese_chou2" msgid="1299112025415343982">"Chou2"</string>
+ <string name="mediasize_japanese_hagaki" msgid="8070115620644254565">"Hagaki"</string>
+ <string name="mediasize_japanese_oufuku" msgid="6049065587307896564">"Oufuku"</string>
+ <string name="mediasize_japanese_kahu" msgid="6872696027560065173">"Kahu"</string>
+ <string name="mediasize_japanese_kaku2" msgid="2359077233775455405">"Kaku2"</string>
+ <string name="mediasize_japanese_you4" msgid="2091777168747058008">"You4"</string>
+ <string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Nepoznata veličina, uspravno"</string>
+ <string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Nepoznata veličina, vodoravno"</string>
+ <string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Otkazano je"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Greška pri ispisivanju sadržaja"</string>
+ <string name="reason_unknown" msgid="6048913880184628119">"nepoznato"</string>
+ <string name="reason_service_unavailable" msgid="7824008732243903268">"Usluga štampanja nije omogućena"</string>
+ <string name="print_service_installed_title" msgid="2246317169444081628">"Usluga <xliff:g id="NAME">%s</xliff:g> je instalirana"</string>
+ <string name="print_service_installed_message" msgid="5897362931070459152">"Dodirnite da biste omogućili"</string>
+ <string name="restr_pin_enter_admin_pin" msgid="783643731895143970">"Unesite PIN administratora"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"Unesite PIN"</string>
+ <string name="restr_pin_incorrect" msgid="8571512003955077924">"Netačno"</string>
+ <string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"Aktuelni PIN"</string>
+ <string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
+ <string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdite novi PIN"</string>
+ <string name="restr_pin_create_pin" msgid="8017600000263450337">"Napravite PIN za izmenu ograničenja"</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora da sadrži najmanje 4 cifre."</string>
+ <plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
+ <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
+ <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+ <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+ </plurals>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
+ <string name="immersive_cling_title" msgid="8394201622932303336">"Prikazuje se ceo ekran"</string>
+ <string name="immersive_cling_description" msgid="3482371193207536040">"Da biste izašli, prevucite nadole odozgo."</string>
+ <string name="immersive_cling_positive" msgid="5016839404568297683">"Važi"</string>
+ <string name="done_label" msgid="2093726099505892398">"Gotovo"</string>
+ <string name="hour_picker_description" msgid="6698199186859736512">"Kružni klizač za sate"</string>
+ <string name="minute_picker_description" msgid="8606010966873791190">"Kružni klizač za minute"</string>
+ <string name="select_hours" msgid="6043079511766008245">"Izaberite sate"</string>
+ <string name="select_minutes" msgid="3974345615920336087">"Izaberite minute"</string>
+ <string name="select_day" msgid="7774759604701773332">"Izaberite mesec i dan"</string>
+ <string name="select_year" msgid="7952052866994196170">"Izaberite godinu"</string>
+ <string name="deleted_key" msgid="7659477886625566590">"Izbrisali ste <xliff:g id="KEY">%1$s</xliff:g>"</string>
+ <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> na poslu"</string>
+ <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkačili ovaj ekran, istovremeno dodirnite i zadržite Nazad i Pregled."</string>
+ <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da biste otkačili ovaj ekran, dodirnite i zadržite Pregled."</string>
+ <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je zakačena: otkačinjanje nije dozvoljeno na ovom uređaju."</string>
+ <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
+ <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran je otkačen"</string>
+ <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN pre otkačinjanja"</string>
+ <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži šablon za otključavanje pre otkačinjanja"</string>
+ <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži lozinku pre otkačinjanja"</string>
+ <string name="dock_non_resizeble_text" msgid="9156251681042762723">"Veličina aplikacije ne može da se menja, pomerajte je pomoću dva prsta."</string>
+ <string name="package_installed_device_owner" msgid="8420696545959087545">"Instalirao je vaš administrator"</string>
+ <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao je administrator"</string>
+ <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao je vaš admiistrator"</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"Da bi produžila vreme trajanja baterije, ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Imejl, razmena poruka i druge aplikacije koje se oslanjaju na sinhronizaciju možda neće da se ažuriraju ako ih ne otvorite.\n\nUšteda baterije se automatski isključuje kada se uređaj puni."</string>
+ <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
+ <item quantity="one">%1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_summary_short" formatted="false" msgid="6830154222366042597">
+ <item quantity="one">Za %1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">Za %1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">Za %1$d min (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="8152974162096743862">
+ <item quantity="one">%1$d sat (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">%1$d sata (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">%1$d sati (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_summary_short" formatted="false" msgid="4787552595253082371">
+ <item quantity="one">Za %1$d s (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="few">Za %1$d s (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="other">za %1$d s (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes" formatted="false" msgid="5127407202506485571">
+ <item quantity="one">%d minut</item>
+ <item quantity="few">%d minuta</item>
+ <item quantity="other">%d minuta</item>
+ </plurals>
+ <plurals name="zen_mode_duration_minutes_short" formatted="false" msgid="2199350154433426128">
+ <item quantity="one">Za %d min</item>
+ <item quantity="few">Za %d min</item>
+ <item quantity="other">Za %d min</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours" formatted="false" msgid="3938821308277433854">
+ <item quantity="one">%d sat</item>
+ <item quantity="few">%d sata</item>
+ <item quantity="other">%d sati</item>
+ </plurals>
+ <plurals name="zen_mode_duration_hours_short" formatted="false" msgid="6748277774662434217">
+ <item quantity="one">Za %d s</item>
+ <item quantity="few">Za %d s</item>
+ <item quantity="other">Za %d s</item>
+ </plurals>
+ <string name="zen_mode_until" msgid="7336308492289875088">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Do <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (sledeći alarm)"</string>
+ <string name="zen_mode_forever" msgid="7420011936770086993">"Dok ne isključite"</string>
+ <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Dok ne isključite režim Ne uznemiravaj"</string>
+ <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
+ <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skupi"</string>
+ <string name="zen_mode_feature_name" msgid="5254089399895895004">"Ne uznemiravaj"</string>
+ <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Odmor"</string>
+ <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Radni dan uveče"</string>
+ <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Vikend"</string>
+ <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Događaj"</string>
+ <string name="muted_by" msgid="6147073845094180001">"Zvuk je isključio/la <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
+ <string name="system_error_wipe_data" msgid="6608165524785354962">"Došlo je do internog problema u vezi sa uređajem i možda će biti nestabilan dok ne obavite resetovanje na fabrička podešavanja."</string>
+ <string name="system_error_manufacturer" msgid="8086872414744210668">"Došlo je do internog problema u vezi sa uređajem. Potražite detalje od proizvođača."</string>
+ <string name="stk_cc_ussd_to_dial" msgid="5202342984749947872">"USSD zahtev je promenjen u DIAL zahtev."</string>
+ <string name="stk_cc_ussd_to_ss" msgid="2345360594181405482">"USSD zahtev je promenjen u SS zahtev."</string>
+ <string name="stk_cc_ussd_to_ussd" msgid="7466087659967191653">"USSD zahtev je promenjen u novi USSD zahtev."</string>
+ <string name="stk_cc_ss_to_dial" msgid="2151304435775557162">"SS zahtev je promenjen u DIAL zahtev."</string>
+ <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtev je promenjen u USSD zahtev."</string>
+ <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtev je promenjen u novi SS zahtev."</string>
+ <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za Work"</string>
+ <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB port za periferijske uređaje"</string>
+ <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
+ <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB port za periferijske uređaje"</string>
+ <string name="floating_toolbar_open_overflow_description" msgid="4797287862999444631">"Još opcija"</string>
+ <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Zatvori preklopni meni"</string>
+ <string name="maximize_button_text" msgid="7543285286182446254">"Uvećaj"</string>
+ <string name="close_button_text" msgid="3937902162644062866">"Zatvori"</string>
+ <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
+ <item quantity="one">Izabrana je <xliff:g id="COUNT_1">%1$d</xliff:g> stavka</item>
+ <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
+ <item quantity="other">Izabrano je <xliff:g id="COUNT_1">%1$d</xliff:g> stavki</item>
+ </plurals>
+ <string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
+ <string name="importance_from_topic" msgid="3572280439880023233">"Vi podešavate važnost ovih obaveštenja."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
+</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index fc0317a..301e1e3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Заключване сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Системно от Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Личен"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролиране на вибрирането"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Разрешава на приложението да контролира устройството за вибрация."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Разрешава на приложението да контролира фенерчето."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Разрешава на приложението да се обажда без ваша намеса до телефонни номера, което може да доведе до неочаквано таксуване или обаждания. Обърнете внимание, че това не му позволява да извършва обаждания до спешните служби. Злонамерените приложения могат да ви въвлекат в разходи, като извършват обаждания без потвърждение от ваша страна."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"достъп до услугата за незабавни съобщения за обаждания"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Изрязване"</string>
<string name="copy" msgid="2681946229533511987">"Копиране"</string>
<string name="paste" msgid="5629880836805036433">"Поставяне"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Поставяне като неформатиран текст"</string>
<string name="replace" msgid="5781686059063148930">"Замяна..."</string>
<string name="delete" msgid="6098684844021697789">"Изтриване"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копиране на URL адреса"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Избор на текст"</string>
+ <string name="undo" msgid="7905788502491742328">"Отмяна"</string>
+ <string name="redo" msgid="7759464876566803888">"Възстановяване"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Избиране на текст"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Добавяне в речника"</string>
<string name="deleteText" msgid="6979668428458199034">"Изтриване"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промяна на тапета"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известия"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Доставчик на условия"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помощник за известия"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN е активирана"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана от <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Докоснете за управление на мрежата."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Актуализирано от администратора ви"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Изтрито от администратора ви"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Важност"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: Тези известия никога да не се показват"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Маловажно: Показване без звуков сигнал в долната част на списъка с известия"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: Тези известия да се показват без звуков сигнал"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Важно: Показване в горната част на списъка с известия и издаване на звуков сигнал"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Спешно: Показване на екрана и издаване на звуков сигнал"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">За една минута (до <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index bbec615..9c88d44 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"এখনই লক করুন"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"৯৯৯+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>টি)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
<string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ব্যক্তিগত"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্রণ করুন"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ফ্ল্যাশলাইট নিয়ন্ত্রণ করে"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"অ্যাপ্লিকেশানকে টর্চলাইট নিয়ন্ত্রণ করতে দেয়৷"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"কাটুন"</string>
<string name="copy" msgid="2681946229533511987">"অনুলিপি"</string>
<string name="paste" msgid="5629880836805036433">"আটকান"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"প্লেইন টেক্সট হিসাবে আটকান"</string>
<string name="replace" msgid="5781686059063148930">"প্রতিস্থাপন করুন..."</string>
<string name="delete" msgid="6098684844021697789">"মুছুন"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL অনুলিপি করুন"</string>
<string name="selectTextMode" msgid="1018691815143165326">"পাঠ্য নির্বাচন করুন"</string>
+ <string name="undo" msgid="7905788502491742328">"পূর্বাবস্থায় ফিরুন"</string>
+ <string name="redo" msgid="7759464876566803888">"পুনরায় করুন"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"পাঠ্য নির্বাচন"</string>
<string name="addToDictionary" msgid="4352161534510057874">"অভিধানে যুক্ত করুন"</string>
<string name="deleteText" msgid="6979668428458199034">"মুছুন"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ওয়ালপেপার পরিবর্তন করুন"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"বিজ্ঞপ্তির শ্রোতা"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"শর্ত প্রদানকারী"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"বিজ্ঞপ্তি সহায়ক"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN সক্রিয়"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> এর দ্বারা VPN সক্রিয় করা হয়েছে"</string>
<string name="vpn_text" msgid="3011306607126450322">"নেটওয়ার্ক পরিচালনা করতে স্পর্শ করুন৷"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"আপনার প্রশাসক দ্বারা আপডেট করা হয়েছে"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"আপনার প্রশাসক দ্বারা মুছে ফেলা হয়েছে"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ব্যাটরির লাইফ উন্নত করতে সহায়তা করতে, ব্যাটারি সাশ্রয়কারী আপনার ডিভাইসের কার্যসম্পাদনা হ্রাস করে এবং কম্পন, অবস্থান পরিষেবাসমূহ এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে৷ ইমেল, বার্তাপ্রেরণ এবং অন্যান্য অ্যাপ্লিকেশানগুলিকে যেগুলি সিঙ্কের উপর নির্ভর করে সেগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে৷\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সাশ্রয়কারী স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়৷"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"অবরুদ্ধ: এই বিজ্ঞপ্তিগুলি কখনই দেখানো হবে না"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"নিম্ন: বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে প্রদর্শন করা হয়"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"সাধারন: এই বিজ্ঞপ্তিগুলি নিঃশব্দে প্রদর্শন করা হয়"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"উচ্চ: বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"জরুরী: স্ক্রীনের উপরে প্রদর্শিত হয় এবং শব্দ করে"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
<item quantity="other">%1$d মিনিটের জন্য (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> পর্যন্ত)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি নির্বাচন করা হয়েছে</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"বিবিধ"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 13109f5..8554b843 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloqueja ara"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"+999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibració"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet que l\'aplicació controli el vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controla la llanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet que l\'aplicació controli la llanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet que l\'aplicació truqui a números de telèfon sense la teva intervenció. Aquesta acció pot produir càrrecs o trucades inesperades. Tingues en compte que això no permet que l\'aplicació truqui a números d\'emergència. Les aplicacions malicioses poden fer trucades sense la teva confirmació, cosa que et pot fer gastar diners."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accés al servei de trucades IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Retalla"</string>
<string name="copy" msgid="2681946229533511987">"Copia"</string>
<string name="paste" msgid="5629880836805036433">"Enganxa"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Enganxa com a text sense format"</string>
<string name="replace" msgid="5781686059063148930">"Vols substituir..."</string>
<string name="delete" msgid="6098684844021697789">"Suprimeix"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copia l\'URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selecciona el text"</string>
+ <string name="undo" msgid="7905788502491742328">"Desfés"</string>
+ <string name="redo" msgid="7759464876566803888">"Refés"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecció de text"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Afegeix al diccionari"</string>
<string name="deleteText" msgid="6979668428458199034">"Suprimeix"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Canvia el fons de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Oient de notificacions"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveïdor de condicions"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistent de notificacions"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ha activat VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca per gestionar la xarxa."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"L\'administrador l\'ha actualitzat"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"L\'administrador ho ha suprimit"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Per tal d\'augmentar la durada de la bateria, la funció d\'estalvi de bateria redueix el rendiment del dispositiu i en limita la vibració i la majoria de dades en segon pla. És possible que el correu electrònic, la missatgeria i la resta d\'aplicacions que se sincronitzen amb freqüència no s\'actualitzin llevat que les obris.\n\nL\'estalvi de bateria es desactiva automàticament mentre el dispositiu s\'està carregant."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquejada: no mostra mai aquestes notificacions"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostra aquestes notificacions de manera silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostra a la part superior de la llista de notificacions i emet un so"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: mostra a la pantalla i emet un so"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Durant %1$d minuts (fins a les <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Durant 1 minut (fins a les <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">Seleccionats: <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Altres"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Tu has definit la importància d\'aquestes notificacions."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ea94aff..2eca49a 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Zamknout"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobní"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Vyjmout"</string>
<string name="copy" msgid="2681946229533511987">"Kopírovat"</string>
<string name="paste" msgid="5629880836805036433">"Vložit"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Vložit jako prostý text"</string>
<string name="replace" msgid="5781686059063148930">"Nahradit•"</string>
<string name="delete" msgid="6098684844021697789">"Smazat"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopírovat adresu URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Vybrat text"</string>
+ <string name="undo" msgid="7905788502491742328">"Vrátit zpět"</string>
+ <string name="redo" msgid="7759464876566803888">"Opakovat"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Výběr textu"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Přidat do slovníku"</string>
<string name="deleteText" msgid="6979668428458199034">"Smazat"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Změnit tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikace poslouchající oznámení"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovatel podmínky"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent oznámení"</string>
<string name="vpn_title" msgid="19615213552042827">"Síť VPN je aktivována"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikace <xliff:g id="APP">%s</xliff:g> aktivovala síť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykem zobrazíte správu sítě."</string>
@@ -1458,13 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizováno administrátorem"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Smazáno administrátorem"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokováno: Tato oznámení nikdy nezobrazovat"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Nízká: Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normální: Tato oznámení zobrazovat bez zvukového upozornění"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Vysoká: Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgentní: Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="few">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="many">%1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1548,8 +1544,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> položka</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Různé"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Důležitost oznámení určujete vy."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 73e9990..2a719b0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillader, at appen kan kontrollere lommelygten."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Klip"</string>
<string name="copy" msgid="2681946229533511987">"Kopier"</string>
<string name="paste" msgid="5629880836805036433">"Indsæt"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Indsæt som almindelig tekst"</string>
<string name="replace" msgid="5781686059063148930">"Erstat..."</string>
<string name="delete" msgid="6098684844021697789">"Slet"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopier webadresse"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Markér tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Fortryd"</string>
+ <string name="redo" msgid="7759464876566803888">"Annuller fortryd"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstmarkering"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Føj til ordbog"</string>
<string name="deleteText" msgid="6979668428458199034">"Slet"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skift baggrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Underretningslytter"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tjeneste til formidling af betingelser"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Underretningsassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktiveret."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveres af <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryk for at administrere netværket."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Opdateret af administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet af din administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeret: Vis aldrig disse underretninger"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Lav: Vis lydløst nederst på listen over underretninger"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Vis disse underretninger lydløst"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Høj: Vis øverst på listen over underretninger, og giv lyd"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Presserende: Vis på skærmen, og giv lyd"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">I %1$d minutter (indtil <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valgt</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Du angiver, hvor vigtige disse underretninger er."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index a1bd45c..d116a24 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Jetzt sperren"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Privat"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Vibrationsalarm steuern"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ermöglicht der App, die Lichtanzeige zu steuern"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne Ihr Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachten Sie, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne Ihre Bestätigung tätigen."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Zugriff auf IMS-Anrufdienst"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Ausschneiden"</string>
<string name="copy" msgid="2681946229533511987">"Kopieren"</string>
<string name="paste" msgid="5629880836805036433">"Einfügen"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Nur Text einfügen"</string>
<string name="replace" msgid="5781686059063148930">"Ersetzen..."</string>
<string name="delete" msgid="6098684844021697789">"Löschen"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL kopieren"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Text auswählen"</string>
+ <string name="undo" msgid="7905788502491742328">"Rückgängig machen"</string>
+ <string name="redo" msgid="7759464876566803888">"Wiederholen"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Textauswahl"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Zum Wörterbuch hinzufügen"</string>
<string name="deleteText" msgid="6979668428458199034">"Löschen"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Hintergrund ändern"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Benachrichtigungs-Listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Bedingungsprovider"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Benachrichtigungsassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wurde von <xliff:g id="APP">%s</xliff:g> aktiviert."</string>
<string name="vpn_text" msgid="3011306607126450322">"Zum Verwalten des Netzwerks berühren"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Von Ihrem Administrator aktualisiert"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Von Ihrem Administrator gelöscht"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf Ihrem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn Ihr Gerät aufgeladen wird."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockiert: Keine Benachrichtigungen anzeigen"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Niedrig: Benachrichtigungen ganz unten in der Benachrichtigungsliste und ohne Ton anzeigen"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Benachrichtigungen ohne Ton anzeigen"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Hoch: Benachrichtigungen ganz oben in der Benachrichtigungsliste und mit Ton anzeigen"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Dringend: Mit Ton auf dem Display einblenden"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d Minuten (bis <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">1 Minute (bis <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ausgewählt</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Sonstige"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Du legst die Wichtigkeit dieser Benachrichtigungen fest."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index f0b1bf9..8116b16 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Κλείδωμα τώρα"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
<string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
<string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Προσωπικό"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Αποκοπή"</string>
<string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string>
<string name="paste" msgid="5629880836805036433">"Επικόλληση"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Επικόλληση ως απλό κείμενο"</string>
<string name="replace" msgid="5781686059063148930">"Αντικατάσταση..."</string>
<string name="delete" msgid="6098684844021697789">"Διαγραφή"</string>
<string name="copyUrl" msgid="2538211579596067402">"Αντιγραφή διεύθυνσης URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Επιλογή κειμένου"</string>
+ <string name="undo" msgid="7905788502491742328">"Αναίρεση"</string>
+ <string name="redo" msgid="7759464876566803888">"Επανάληψη"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Επιλογή κειμένου"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Προσθήκη στο λεξικό"</string>
<string name="deleteText" msgid="6979668428458199034">"Διαγραφή"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Αλλαγή ταπετσαρίας"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Υπηρεσία ακρόασης ειδοποίησης"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Πάροχος συνθηκών"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Βοηθός ειδοποιήσεων"</string>
<string name="vpn_title" msgid="19615213552042827">"Το VPN ενεργοποιήθηκε"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Το VPN ενεργοποιήθηκε από την εφαρμογή <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Αγγίξτε για τη διαχείριση του δικτύου."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ενημερώθηκε από το διαχειριστή σας"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Διαγράφηκε από το διαχειριστή σας"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στο συγχρονισμό ενδέχεται να μην ενημερώνονται έως ότου τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα όταν η συσκευή σας φορτίζει."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Αποκλεισμένες: Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Χαμηλής βαρύτητας: Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τη συνοδεία ήχου"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Κανονική βαρύτητα: Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Υψηλής βαρύτητας: Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων συνοδευόμενες από κάποιον ήχο"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Επείγουσες: Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Για %1$d λεπτά (έως τις <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Για ένα λεπτό (έως τις <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">Επιλέχτηκε <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Διάφορα"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 9350ef72..930c310 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cut"</string>
<string name="copy" msgid="2681946229533511987">"Copy"</string>
<string name="paste" msgid="5629880836805036433">"Paste"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
<string name="replace" msgid="5781686059063148930">"Replace..."</string>
<string name="delete" msgid="6098684844021697789">"Delete"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+ <string name="undo" msgid="7905788502491742328">"Undo"</string>
+ <string name="redo" msgid="7759464876566803888">"Redo"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9350ef72..930c310 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cut"</string>
<string name="copy" msgid="2681946229533511987">"Copy"</string>
<string name="paste" msgid="5629880836805036433">"Paste"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
<string name="replace" msgid="5781686059063148930">"Replace..."</string>
<string name="delete" msgid="6098684844021697789">"Delete"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+ <string name="undo" msgid="7905788502491742328">"Undo"</string>
+ <string name="redo" msgid="7759464876566803888">"Redo"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9350ef72..930c310 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cut"</string>
<string name="copy" msgid="2681946229533511987">"Copy"</string>
<string name="paste" msgid="5629880836805036433">"Paste"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Paste as plain text"</string>
<string name="replace" msgid="5781686059063148930">"Replace..."</string>
<string name="delete" msgid="6098684844021697789">"Delete"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copy URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Select text"</string>
+ <string name="undo" msgid="7905788502491742328">"Undo"</string>
+ <string name="redo" msgid="7759464876566803888">"Redo"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Text selection"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Add to dictionary"</string>
<string name="deleteText" msgid="6979668428458199034">"Delete"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Change wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Condition provider"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activated"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN is activated by <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Touch to manage the network."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Updated by your administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Deleted by your administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Importance"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocked: Never show these notifications"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Low: Silently show at the bottom of the notification list"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Silently show these notifications"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"High: Show at the top of the notifications list and make sound"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: Peek onto the screen and make sound"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">For %1$d minutes (until <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">For one minute (until <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7369278..258ef33 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio IMS para realizar llamadas"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Pegar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sin formato"</string>
<string name="replace" msgid="5781686059063148930">"Reemplazar..."</string>
<string name="delete" msgid="6098684844021697789">"Eliminar"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
+ <string name="redo" msgid="7759464876566803888">"Rehacer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Agregar al diccionario"</string>
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Agente de escucha de notificaciones"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN está activado por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por el administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Lo eliminó el administrador."</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización no puedan actualizarse, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar nunca estas notificaciones"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificación sin emitir sonido"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de manera silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar en la pantalla y emitir sonido"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Durante %1$d minutos hasta la(s) <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g></item>
<item quantity="one">Durante 1 minuto; hasta la(s) <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g></item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento seleccionado</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Estableciste la importancia de estas notificaciones."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 420981b..9848bb6 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear ahora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"> 999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la función de vibración."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio de llamadas IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Pegar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sin formato"</string>
<string name="replace" msgid="5781686059063148930">"Sustituir..."</string>
<string name="delete" msgid="6098684844021697789">"Eliminar"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Deshacer"</string>
+ <string name="redo" msgid="7759464876566803888">"Rehacer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Añadir al diccionario"</string>
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Detector de notificaciones"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Proveedor de condiciones"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificaciones"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca para administrar la red."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: no mostrar estas notificaciones"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baja: mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificaciones de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar en la pantalla y emitir sonido"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Durante %1$d minutos (hasta las <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Durante un minuto (hasta las <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> seleccionado</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Tú determinas la importancia de estas notificaciones."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
</resources>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index ffaa4df..466bd5d 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukusta kohe"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
<string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Isiklik"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"juhtige vibreerimist"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Võimaldab rakendusel juhtida vibreerimist."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"juhi taskulampi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Võimaldab rakendusel juhtida taskulampi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"helista otse telefoninumbritele"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Võimaldab rakendusel teie sekkumiseta telefoninumbritele helistada. See võib põhjustada ootamatuid tasusid või telefonikõnesid. Pange tähele, et see ei luba rakendusel helistada hädaabinumbritele. Pahatahtlikud rakendused võivad teile kulusid tekitada, tehes telefonikõnesid teie kinnituseta."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"juurdepääs IMS-kõneteenusele"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Lõika"</string>
<string name="copy" msgid="2681946229533511987">"Kopeeri"</string>
<string name="paste" msgid="5629880836805036433">"Kleebi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Kleebi lihttekstina"</string>
<string name="replace" msgid="5781686059063148930">"Asenda..."</string>
<string name="delete" msgid="6098684844021697789">"Kustuta"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopeeri URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Valige tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Võta tagasi"</string>
+ <string name="redo" msgid="7759464876566803888">"Tee uuesti"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksti valimine"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Lisa sõnastikku"</string>
<string name="deleteText" msgid="6979668428458199034">"Kustuta"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Muutke taustapilti"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Märguannete kuulamisteenus"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Tingimuse pakkuja"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Märguannete abi"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN on aktiveeritud"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-i aktiveeris <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Võrgu haldamiseks puudutage."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Värskendas administraator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Kustutas teie administraator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeeritud: ära kunagi näita neid märguandeid"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Madal: kuva vaikselt märguannete loendi allosas"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Tavaline: kuva need märguanded vaikselt"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Kõrge: kuva märguannete loendi ülaosas koos heliga"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Kiireloomuline: kuva ekraani servas koos heliga"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d minutiks (kuni <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Üheks minutiks (kuni <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> on valitud</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Mitmesugust"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Teie määrasite nende märguannete tähtsuse."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
</resources>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index d32a0818..cdb8622 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Blokeatu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
<string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"bibrazioa kontrolatzea"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Bibragailua kontrolatzea baimentzen die aplikazioei."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolatu linterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Linterna kontrolatzea baimentzen die aplikazioei."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string>
@@ -383,8 +382,8 @@
<string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Tabletak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
<string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Telebistak ezagutzen dituen kontuen zerrenda lortzea baimentzen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak sar daitezke."</string>
<string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Telefonoak ezagutzen dituen kontuen zerrenda lortzeko baimena ematen die aplikazioei. Instalatuta dituzun aplikazioek sortutako kontuak har daitezke barne."</string>
- <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sare-konexioak ikustea"</string>
- <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sare-konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
+ <string name="permlab_accessNetworkState" msgid="4951027964348974773">"sareko konexioak ikustea"</string>
+ <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Sareko konexioei buruzko informazioa ikusteko baimena ematen die aplikazioei; adibidez, zer sare dauden eta zeintzuk dauden konektatuta."</string>
<string name="permlab_createNetworkSockets" msgid="7934516631384168107">"Izan sarerako sarbide osoa"</string>
<string name="permdesc_createNetworkSockets" msgid="3403062187779724185">"Sare-socketak sortzeko eta sare-protokolo pertsonalizatuak erabiltzeko baimena ematen die aplikazioei. Arakatzaileak eta beste aplikazio batzuek Internetera konektatzeko moduak eskaintzen dituzte, beraz, baimen hori ez da beharrezkoa datuak Internetera bidaltzeko."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"aldatu sarearen konektagarritasuna"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Ebaki"</string>
<string name="copy" msgid="2681946229533511987">"Kopiatu"</string>
<string name="paste" msgid="5629880836805036433">"Itsatsi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Itsatsi testu arrunt gisa"</string>
<string name="replace" msgid="5781686059063148930">"Ordeztu…"</string>
<string name="delete" msgid="6098684844021697789">"Ezabatu"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiatu URLa"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Hautatu testua"</string>
+ <string name="undo" msgid="7905788502491742328">"Desegin"</string>
+ <string name="redo" msgid="7759464876566803888">"Berregin"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Testua hautatzea"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Gehitu hiztegian"</string>
<string name="deleteText" msgid="6979668428458199034">"Ezabatu"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Aldatu horma-papera"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Jakinarazpenak hautemateko zerbitzua"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Baldintza-hornitzailea"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Jakinarazpenen laguntzailea"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN eginbidea aktibatuta"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> aplikazioak VPN konexioa aktibatu du"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ukitu sarea kudeatzeko."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren funtzionamendua, dardara, kokapen-zerbitzuak eta atzeko planoko datuen erabilera gehiena mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzen ezarri orduko desaktibatzen da bateria-aurrezlea."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokeatuta: ez erakutsi jakinarazpen hauek"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Txikia: erakutsi jakinarazpen hauek zerrendaren behealdean"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normala: erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Handia: erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Premiazkoa: agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d minutuz (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> arte)</item>
<item quantity="one">Minutu batez (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> arte)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> hautatuta</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Askotarikoak"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Zuk ezarri zenuen jakinarazpen hauen garrantzia."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cf6df8e..b0da5fe 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"اکنون قفل شود"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"بیشتر از 999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
<string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
<string name="android_system_label" msgid="6577375335728551336">"سیستم Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"شخصی"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه میدهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه میدهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"کنترل لرزش"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"به برنامه اجازه میدهد تا لرزاننده را کنترل کند."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"به برنامه اجازه میدهد تا چراغ قوه را کنترل کند."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفنها"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"به برنامه اجازه میدهد بدون دخالت شما با شمارههای تلفن تماس بگیرد. این ممکن است باعث ایجاد هزینه یا تماسهای پیشبینی نشده شود. توجه داشته باشید که این به برنامه اجازه نمیدهد به برقراری تماسهای اضطراری بپردازد. برنامههای مخرب ممکن است با برقراری تماس بدون تأیید شما هزینههایی را برای شما ایجاد کنند."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"دسترسی به سرویس تماس IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"برش"</string>
<string name="copy" msgid="2681946229533511987">"کپی"</string>
<string name="paste" msgid="5629880836805036433">"جای گذاری"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"جایگذاری به عنوان متن ساده"</string>
<string name="replace" msgid="5781686059063148930">"جایگزین شود..."</string>
<string name="delete" msgid="6098684844021697789">"حذف"</string>
<string name="copyUrl" msgid="2538211579596067402">"کپی URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"انتخاب متن"</string>
+ <string name="undo" msgid="7905788502491742328">"لغو"</string>
+ <string name="redo" msgid="7759464876566803888">"انجام مجدد"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"انتخاب متن"</string>
<string name="addToDictionary" msgid="4352161534510057874">"افزودن به فرهنگلغت"</string>
<string name="deleteText" msgid="6979668428458199034">"حذف"</string>
@@ -892,7 +894,7 @@
<string name="whichHomeApplicationNamed" msgid="4493438593214760979">"استفاده از %1$s به عنوان برنامه صفحه اصلی"</string>
<string name="alwaysUse" msgid="4583018368000610438">"استفاده به صورت پیشفرض برای این عملکرد."</string>
<string name="use_a_different_app" msgid="8134926230585710243">"استتفاده از یک برنامه دیگر"</string>
- <string name="clearDefaultHintMsg" msgid="3252584689512077257">"پیشفرض را در تنظیمات سیستم> برنامهها> مورد دانلود شده پاک کنید."</string>
+ <string name="clearDefaultHintMsg" msgid="3252584689512077257">"پیشفرض را در تنظیمات سیستم> برنامهها> مورد بارگیری شده پاک کنید."</string>
<string name="chooseActivity" msgid="7486876147751803333">"انتخاب عملکرد"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"انتخاب برنامه برای دستگاه USB"</string>
<string name="noApplications" msgid="2991814273936504689">"هیچ برنامهای نمیتواند این کار را انجام دهد."</string>
@@ -914,7 +916,7 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> از ابتدا راهاندازی شد."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"مقیاس"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"همیشه نشان داده شود"</string>
- <string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد دانلود شده آن را دوباره فعال کنید."</string>
+ <string name="screen_compat_mode_hint" msgid="1064524084543304459">"در تنظیمات سیستم >برنامهها > مورد بارگیری شده آن را دوباره فعال کنید."</string>
<string name="smv_application" msgid="3307209192155442829">"برنامه <xliff:g id="APPLICATION">%1$s</xliff:g> (پردازش <xliff:g id="PROCESS">%2$s</xliff:g>) خطمشی StrictMode اجرایی خود را نقض کرده است."</string>
<string name="smv_process" msgid="5120397012047462446">"فرآیند <xliff:g id="PROCESS">%1$s</xliff:g> خطمشی StrictMode اجرای خودکار خود را نقض کرده است."</string>
<string name="android_upgrading_title" msgid="1584192285441405746">"Android در حال ارتقا است..."</string>
@@ -927,7 +929,7 @@
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> در حال اجرا"</string>
<string name="heavy_weight_notification_detail" msgid="1721681741617898865">"لمس کردن برای بازکردن برنامه"</string>
<string name="heavy_weight_switcher_title" msgid="7153167085403298169">"برنامه عوض شود؟"</string>
- <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"برنامه دیگری از قبل در حال اجرا است که باید قبل از اینکه برنامه جدیدی را شروع کنید متوقف شود."</string>
+ <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"برنامه دیگری از قبل در حال اجراست که باید متوقف شود تا بتوانید برنامه جدید را شروع کنید."</string>
<string name="old_app_action" msgid="493129172238566282">"بازگشت به <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="old_app_description" msgid="2082094275580358049">"برنامه جدید شروع نشود."</string>
<string name="new_app_action" msgid="5472756926945440706">"شروع <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"تغییر کاغذدیواری"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"شنونده اعلان"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ارائهدهنده وضعیت"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"دستیار اعلان"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN فعال شد"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN توسط <xliff:g id="APP">%s</xliff:g> فعال شده است"</string>
<string name="vpn_text" msgid="3011306607126450322">"برای مدیریت شبکه لمس کنید."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"توسط سرپرست شما بهروزرسانی شد"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"توسط سرپرستتان حذف شد"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود عمر باتری، بهینهسازی باتری عملکرد دستگاهتان را کاهش میدهد و لرزش، سرویسهای مبتنی بر مکان، و دسترسی به اکثر دادهها در پسزمینه را محدود میکند. ایمیل، پیامرسانی و برنامههای دیگری که به همگامسازی وابستهاند، تا زمانیکه آنها را باز نکنید نمیتوانند بهروز شوند.\n\nبهینهسازی باتری بهصورت خودکار در هنگام شارژ شدن دستگاه خاموش میشود."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود: هرگز این اعلانها نشان داده نشود"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"پایین: بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"عادی: این اعلانها بدون صدا نشان داده شود"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"بالا: در بالای فهرست اعلانها و به همراه صدا نشان داده شود"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ضروری: نمای کلی به همراه صدا در صفحه نشان داده شود"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">به مدت %1$d دقیقه (تا <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> انتخاب شد</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"متفرقه"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"شما اهمیت این اعلانها را تنظیم میکنید."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index eea796e..f7db678 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lukitse nyt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
<string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Henkilökoht."</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"hallitse värinää"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Antaa sovelluksen hallita värinää."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Antaa sovelluksen hallita taskulamppua."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Antaa sovelluksen soittaa puhelinnumeroihin kysymättä sinulta. Tämä voi aiheuttaa odottamattomia kuluja tai puheluita. Huomaa, että tämä ei anna sovellukselle lupaa soittaa hätänumeroihin. Haitalliset sovellukset voivat aiheuttaa sinulle kuluja soittamalla puheluita ilman lupaa."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pikaviestipalvelun puhelukäyttöoikeus"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Leikkaa"</string>
<string name="copy" msgid="2681946229533511987">"Kopioi"</string>
<string name="paste" msgid="5629880836805036433">"Liitä"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Liitä pelkkänä tekstinä"</string>
<string name="replace" msgid="5781686059063148930">"Korvaa..."</string>
<string name="delete" msgid="6098684844021697789">"Poista"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopioi URL-osoite"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Valitse tekstiä"</string>
+ <string name="undo" msgid="7905788502491742328">"Kumoa"</string>
+ <string name="redo" msgid="7759464876566803888">"Toista"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstin valinta"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Lisää sanakirjaan"</string>
<string name="deleteText" msgid="6979668428458199034">"Poista"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Vaihda taustakuvaa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ilmoituskuuntelija"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ehtojen toimituspalvelu"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ilmoitusapuri"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN on aktivoitu"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> on aktivoinut VPN-yhteyden"</string>
<string name="vpn_text" msgid="3011306607126450322">"Voit hallinnoida verkkoa koskettamalla."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Järjestelmänvalvojasi on päivittänyt paketin."</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Järjestelmänvalvoja on poistanut paketin."</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Estetty: älä koskaan näytä näitä ilmoituksia."</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Matala: näytä nämä ilmoitukset huomaamattomasti luettelon alaosassa."</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Tavallinen: näytä nämä ilmoitukset huomaamattomasti."</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Korkea: näytä nämä ilmoitukset luettelon yläosassa ja toista äänimerkki."</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Kiireellinen: näytä ilmoitus näytöllä ja toista äänimerkki."</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Yhdeksi minuutiksi (kunnes kello on <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> valittu</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Muut"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Voit valita näiden ilmoitusten tärkeyden."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 3afdcc0..50aed95 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"gérer le vibreur"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"gérer la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de gérer la lampe de poche."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement des numéros de téléphone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Couper"</string>
<string name="copy" msgid="2681946229533511987">"Copier"</string>
<string name="paste" msgid="5629880836805036433">"Coller"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Coller en texte brut"</string>
<string name="replace" msgid="5781686059063148930">"Remplacer..."</string>
<string name="delete" msgid="6098684844021697789">"Supprimer"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Sélectionner du texte"</string>
+ <string name="undo" msgid="7905788502491742328">"Annuler"</string>
+ <string name="redo" msgid="7759464876566803888">"Répéter"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Sélection de texte"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Ajouter au dictionnaire"</string>
<string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant des notifications"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\n L\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Élevée : afficher en haut de la liste des notifications et émettre un son"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent : afficher sur l\'écran et émettre un son"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 7ea8283..33d2016 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -189,7 +189,7 @@
<string name="silent_mode_ring" msgid="8592241816194074353">"Sonnerie activée"</string>
<string name="reboot_to_update_title" msgid="6212636802536823850">"Mise à jour du système Android"</string>
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"Préparation de la mise à jour en cours…"</string>
- <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mises à jour en cours…"</string>
+ <string name="reboot_to_update_package" msgid="3871302324500927291">"Traitement du package de mise à jour…"</string>
<string name="reboot_to_update_reboot" msgid="6428441000951565185">"Redémarrage en cours…"</string>
<string name="reboot_to_reset_title" msgid="4142355915340627490">"Rétablir la configuration d\'usine"</string>
<string name="reboot_to_reset_message" msgid="2432077491101416345">"Redémarrage en cours…"</string>
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Verrouiller"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
<string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personnel"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"contrôler le vibreur"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de contrôler le vibreur."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"contrôler la lampe de poche"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de contrôler la lampe de poche."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Couper"</string>
<string name="copy" msgid="2681946229533511987">"Copier"</string>
<string name="paste" msgid="5629880836805036433">"Coller"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Coller au format texte brut"</string>
<string name="replace" msgid="5781686059063148930">"Remplacer..."</string>
<string name="delete" msgid="6098684844021697789">"Supprimer"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copier l\'URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Sélectionner texte"</string>
+ <string name="undo" msgid="7905788502491742328">"Annuler"</string>
+ <string name="redo" msgid="7759464876566803888">"Rétablir"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Sélection de texte"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Ajouter au dictionnaire"</string>
<string name="deleteText" msgid="6979668428458199034">"Supprimer"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Changer de fond d\'écran"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Outil d\'écoute des notifications"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fournisseur de conditions"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistant de notifications"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activé"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN activé par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Appuyez ici pour gérer le réseau."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Mis à jour par votre administrateur"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Supprimé par votre administrateur"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances et désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. Les messageries électroniques ou autres applications utilisant la synchronisation pourraient ne pas se mettre à jour, sauf si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque l\'appareil est en charge."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloquée : ne jamais afficher ces notifications"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Faible : afficher en mode silencieux au bas de la liste de notifications"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normale : afficher ces notifications en mode silencieux"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Élevée : afficher en haut de la liste des notifications et émettre un son"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent : afficher sur l\'écran et émettre un son"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Pendant %1$d minute (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Pendant %1$d minutes (jusqu\'à <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> éléments sélectionnés</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Divers"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Vous définissez l\'importance de ces notifications."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
</resources>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 83ba790..7947825 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar a vibración"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite á aplicación controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar a lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite á aplicación controlar a luz do flash."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chamar directamente aos números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite á aplicación chamar a números de teléfono sen a túa intervención. Esta acción pode implicar chamadas ou custos inesperados. Ten en conta que isto non permite á aplicación chamar a números de emerxencia. É posible que aplicacións maliciosas che custen diñeiro debido á realización de chamadas sen a túa confirmación."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceso ao servizo de chamadas de IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Pegar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Pegar como texto sen formato"</string>
<string name="replace" msgid="5781686059063148930">"Substituír…"</string>
<string name="delete" msgid="6098684844021697789">"Eliminar"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Seleccionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Desfacer"</string>
+ <string name="redo" msgid="7759464876566803888">"Refacer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selección de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Engadir ao dicionario"</string>
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Axente de escoita de notificacións"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condicións"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistente de notificacións"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> activou a VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toca aquí para xestionar a rede."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado polo administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado polo administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función aforro de batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función aforro de batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: non mostrar nunca estas notificacións"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificacións de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificacións e emitir son"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urxente: mostrar na pantalla e emitir son"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Durante %1$d minutos (ata as <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Durante un minuto (ata as <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">Seleccionouse <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Varios"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ti defines a importancia destas notificacións."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
</resources>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index bcb3321..aa9478b 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"હવે લૉક કરો"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"સામગ્રીઓ છુપાવેલ છે"</string>
<string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"વ્યક્તિગત"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"એપ્લિકેશનને કૅમેરા વડે ચિત્રો અને વિડિઓઝ લેવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને તમારી પુષ્ટિ વિના કોઈપણ સમયે કૅમેરાના ઉપયોગની મંજૂરી આપે છે."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"વાઇબ્રેશન નિયંત્રિત કરો"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ફ્લેશલાઇટ નિયંત્રિત કરો"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"એપ્લિકેશનને ફ્લેશલાઇટને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS કૉલ સેવા ઍક્સેસ કરો"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"કાપો"</string>
<string name="copy" msgid="2681946229533511987">"કૉપિ કરો"</string>
<string name="paste" msgid="5629880836805036433">"પેસ્ટ કરો"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"સાદી ટેક્સ્ટ તરીકે પેસ્ટ કરો"</string>
<string name="replace" msgid="5781686059063148930">"બદલો…"</string>
<string name="delete" msgid="6098684844021697789">"કાઢી નાખો"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL ની કૉપિ કરો"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ટેક્સ્ટ પસંદ કરો"</string>
+ <string name="undo" msgid="7905788502491742328">"પૂર્વવત્ કરો"</string>
+ <string name="redo" msgid="7759464876566803888">"ફરી કરો"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ટેક્સ્ટ પસંદગી"</string>
<string name="addToDictionary" msgid="4352161534510057874">"શબ્દકોશમાં ઉમેરો"</string>
<string name="deleteText" msgid="6979668428458199034">"કાઢી નાખો"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"વૉલપેપર બદલો"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"સૂચના સાંભળનાર"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"શરત પ્રદાતા"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"સૂચના સહાયક"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN સક્રિય કર્યું"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> દ્વારા VPN સક્રિય થયું"</string>
<string name="vpn_text" msgid="3011306607126450322">"નેટવર્કને સંચાલિત કરવા માટે ટચ કરો."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ થયેલ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખેલ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"બૅટરી આવરદા વધુ સારી કરવામાં સહાય માટે, બૅટરી સેવર તમારા ઉપકરણના પ્રદર્શનને ઘટાડે છે અને વાઇબ્રેશન, સ્થાન સેવાઓ અને મોટાભાગના પૃષ્ઠભૂમિ ડેટાને સીમિત કરે છે. ઇમેઇલ, મેસેજિંગ અને અન્ય એપ્લિકેશનો જે સમન્વયન પર આધાર રાખે છે તે તમે તેમને ખોલશો નહીં ત્યાં સુધી અપડેટ થઈ શકતી નથી.\n\nજ્યારે તમારું ઉપકરણ ચાર્જ થઈ રહ્યું હોય ત્યારે બૅટરી સેવર આપમેળે બંધ થઈ જાય છે."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"મહત્વ"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"અવરોધિત: આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"નિમ્ન: સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"સામાન્ય: આ સૂચનાઓ ચુપચાપ બતાવો"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ઉચ્ચ: સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"તાત્કાલિક : સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d મિનિટ માટે (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> સુધી)</item>
<item quantity="other">%1$d મિનિટ માટે (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> સુધી)</item>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index ef8be64..d3d1e2c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
<string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ऐप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ऐप्स को आपके हस्तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्याशित शुल्क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्स को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण ऐप्स आपकी पुष्टि के बिना कॉल करके आपका धन व्यय कर सकते हैं."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा ऐक्सेस करें"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"काटें"</string>
<string name="copy" msgid="2681946229533511987">"प्रतिलिपि बनाएं"</string>
<string name="paste" msgid="5629880836805036433">"चिपकाएं"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"सादे पाठ के रूप में चिपकाएं"</string>
<string name="replace" msgid="5781686059063148930">"बदलें•"</string>
<string name="delete" msgid="6098684844021697789">"हटाएं"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL की प्रतिलिपि बनाएं"</string>
<string name="selectTextMode" msgid="1018691815143165326">"लेख को चुनें"</string>
+ <string name="undo" msgid="7905788502491742328">"वापस लाएं"</string>
+ <string name="redo" msgid="7759464876566803888">"फिर से करें"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"लेख चयन"</string>
<string name="addToDictionary" msgid="4352161534510057874">"शब्दकोश में जोड़ें"</string>
<string name="deleteText" msgid="6979668428458199034">"हटाएं"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"नोटिफिकेशन श्रवणकर्ता"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"नोटिफिकेशन सहायक"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबंधित करने के लिए स्पर्श करें."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"आपके नियंत्रक द्वारा अपडेट किया गया"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"आपके नियंत्रक द्वारा हटाया गया"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"बैटरी जीवन काल को बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन, स्थान सेवाओं और अधिकांश पृष्ठभूमि डेटा को सीमित कर देता है. हो सकता है कि ईमेल, संदेश सेवा तथा समन्वयन पर आधारित अन्य ऐप्स तब तक ना खुलें जब तक कि आप उन्हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"महत्व"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित: ये नोटिफिकेशन कभी ना दिखाएं"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"निम्न: नोटिफिकेशन सूची के नीचे मौन रूप से दिखाएं"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"उच्च: नोटिफिकेशन सूची के शीर्ष पर दिखाएं और ध्वनि करें"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"तत्काल: स्क्रीन पर एक झलक देखें और ध्वनि करें"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
<item quantity="other">%1$d मिनट के लिए (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> तक)</item>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0609843..dc55c57 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -224,6 +224,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Zaključaj sada"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
<string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobno"</string>
@@ -354,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"upravljanje vibracijom"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogućuje nadzor nad vibratorom."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"upravljanje svjetiljkom"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogućuje upravljanje svjetiljkom."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogućuje pozivanje telefonskih brojeva bez vašeg sudjelovanja. To može dovesti do neočekivanih troškova ili poziva. Uzmite u obzir da se aplikaciji time ne omogućuje pozivanje brojeva u nuždi. Zlonamjerne aplikacije mogu vam uzrokovati dodatne troškove postavljanjem poziva bez vašeg odobrenja."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristupiti usluzi poziva izravnih poruka"</string>
@@ -863,10 +862,13 @@
<string name="cut" msgid="3092569408438626261">"Izreži"</string>
<string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
<string name="paste" msgid="5629880836805036433">"Zalijepi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Zalijepi kao obični tekst"</string>
<string name="replace" msgid="5781686059063148930">"Zamijeni…"</string>
<string name="delete" msgid="6098684844021697789">"Izbriši"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Odabir teksta"</string>
+ <string name="undo" msgid="7905788502491742328">"Poništi"</string>
+ <string name="redo" msgid="7759464876566803888">"Ponovi"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Odabir teksta"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Dodaj u rječnik"</string>
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
@@ -1114,6 +1116,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Promjena pozadinske slike"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Slušatelj obavijesti"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Davatalj uvjeta"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomoćnik za obavijesti"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> aktivirala je VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
@@ -1449,13 +1452,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurira vaš administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikad ne prikazuj te obavijesti"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Nisko: tiho prikaži na dnu popisa obavijesti"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Uobičajeno: prikazuj te obavijesti tiho"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Visoko: prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Hitno: prikaži na zaslonu i emitiraj zvučni signal"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d minutu (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1530,8 +1526,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> odabranih</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Postavili ste važnost tih obavijesti."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0f3b849..3176c65 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Zárolás most"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
<string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Személyes"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"rezgés szabályozása"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lehetővé teszi az alkalmazás számára, hogy az Ön jóváhagyása nélkül hívjon fel telefonszámokat. Ennek eredményeként váratlan terhelésekkel vagy telefonhívásokkal találkozhat. Vegye figyelembe, hogy ez nem teszi lehetővé segélyhívó számok hívását az alkalmazás számára. A rosszindulatú alkalmazások az Ön jóváhagyása nélkül kezdeményezhetnek hívásokat, így költségek merülhetnek fel."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"hozzáférés az IMS-hívásszolgáltatáshoz"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Kivágás"</string>
<string name="copy" msgid="2681946229533511987">"Másolás"</string>
<string name="paste" msgid="5629880836805036433">"Beillesztés"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Beillesztés egyszerű szövegként"</string>
<string name="replace" msgid="5781686059063148930">"Csere..."</string>
<string name="delete" msgid="6098684844021697789">"Törlés"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL másolása"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Szöveg kijelölése"</string>
+ <string name="undo" msgid="7905788502491742328">"Visszavonás"</string>
+ <string name="redo" msgid="7759464876566803888">"Újra"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Szöveg kijelölése"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Hozzáadás a szótárhoz"</string>
<string name="deleteText" msgid="6979668428458199034">"Törlés"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Háttérkép megváltoztatása"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Értesítésfigyelő"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Feltételbiztosító"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Értesítési segéd"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiválva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A(z) <xliff:g id="APP">%s</xliff:g> aktiválta a VPN-t"</string>
<string name="vpn_text" msgid="3011306607126450322">"Érintse meg a hálózat kezeléséhez."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Frissítette a rendszergazda"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"A rendszergazda törölte"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Fontosság"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Letiltva: soha nem jelennek meg ezek az értesítések"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Alacsony: az értesítések az értesítési lista végén jelennek meg hangjelzés nélkül"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normál: hang nélkül jelennek meg ezek az értesítések"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Magas: az értesítések az értesítési lista elején jelennek meg hangjelzéssel"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Sürgős: az értesítések felugranak a képernyőn hangjelzéssel"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d percen át (eddig: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Egy percen át (eddig: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 3fbdeb9..d72ee8d 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Կողպել հիմա"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
<string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Անձնական"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"կառավարել թրթռումը"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"կառավարել լապտերը"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Թույլ է տալիս հավելվածին կառավարել լապտերը:"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ուղղակիորեն զանգել հեռախոսահամարներին"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Թույլ է տալիս հավելվածին զանգել հեռախոսահամարներին առանց ձեր միջամտության: Սա կարող է հանգեցնել անկանխատեսելի գանձումների կամ զանգերի: Նկատի ունեցեք, որ սա թույլ չի տալիս հավելվածին զանգել արտակարգ իրավիճակների համարներին: Վնասարար հավելվածները կարող են ձեր հաշվից զանգեր կատարել` առանց ձեր հաստատման:"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"օգտվել IMS զանգերի ծառայությունից"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Կտրել"</string>
<string name="copy" msgid="2681946229533511987">"Պատճենել"</string>
<string name="paste" msgid="5629880836805036433">"Տեղադրել"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Տեղադրել որպես սովորական տեքստ"</string>
<string name="replace" msgid="5781686059063148930">"Փոխարինել..."</string>
<string name="delete" msgid="6098684844021697789">"Ջնջել"</string>
<string name="copyUrl" msgid="2538211579596067402">"Պատճենել URL-ը"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Ընտրել տեքստ"</string>
+ <string name="undo" msgid="7905788502491742328">"Հետարկել"</string>
+ <string name="redo" msgid="7759464876566803888">"Կրկնել"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Տեքստի ընտրություն"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Ավելացնել բառարանում"</string>
<string name="deleteText" msgid="6979668428458199034">"Ջնջել"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ծանուցման ունկնդիր"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Պայմանների մատակարար"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ծանուցումների օգնական"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN-ը ակտիվացված է"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-ն ակտիվացված է <xliff:g id="APP">%s</xliff:g>-ի կողմից"</string>
<string name="vpn_text" msgid="3011306607126450322">"Հպեք` ցանցի կառավարման համար:"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ադմինիստրատորը թարմացրել է այն"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Ադմինիստրատորը ջնջել է այն"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու նպատակով, մարտկոցի էներգիայի խնայման գործառույթը սահմանափակում է սարքի աշխատանքը, թրթռոցը, տեղադրության ծառայությունները և հետնաշերտում աշխատող շատ գործընթացներ: Էլփոստը, հաղորդագրությունների փոխանակումը և տվյալների համաժամեցումից կախված այլ հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\nԵրբ ձեր սարքը լիցքավորվում է, մարտկոցի էներգիայի խնայման գործառույթն ինքնաշխատորեն անջատվում է:"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Արգելափակված է. Երբեք չցուցադրել այս ծանուցումները"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Ցածր. Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Նորմալ. Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Բարձր. Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Հրատապ. Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">%1$d րոպե (մինչև <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other">Ընտրված է՝ <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Զանազան"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index d13168a..024eea4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
<string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pribadi"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrol getaran"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Mengizinkan apl mengontrol lampu kilat."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Memungkinkan aplikasi menghubungi nomor telepon tanpa campur tangan Anda. Izin ini dapat mengakibatkan biaya atau panggilan tak terduga. Perhatikan bahwa izin ini tidak memungkinkan aplikasi menghubungi nomor darurat. Aplikasi berbahaya dapat menyebabkan Anda dikenakan biaya dengan melakukan panggilan tanpa konfirmasi Anda."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses layanan panggilan IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Potong"</string>
<string name="copy" msgid="2681946229533511987">"Salin"</string>
<string name="paste" msgid="5629880836805036433">"Tempel"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Tempel sebagai teks biasa"</string>
<string name="replace" msgid="5781686059063148930">"Ganti..."</string>
<string name="delete" msgid="6098684844021697789">"Hapus"</string>
<string name="copyUrl" msgid="2538211579596067402">"Salin URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Pilih teks"</string>
+ <string name="undo" msgid="7905788502491742328">"Urungkan"</string>
+ <string name="redo" msgid="7759464876566803888">"Ulangi"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Pemilihan teks"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Tambahkan ke kamus"</string>
<string name="deleteText" msgid="6979668428458199034">"Hapus"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ubah wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Penyedia ketentuan"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asisten notifikasi"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengelola jaringan."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Diperbarui oleh administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Dihapus oleh administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Tingkat Kepentingan"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Diblokir: Jangan pernah menampilkan notifikasi ini"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Menampilkan di bagian bawah daftar notifikasi secara diam-diam"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Menampilkan notifikasi ini secara diam-diam"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Tinggi: Menampilkan di bagian atas daftar notifikasi dan membunyikan suara"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Darurat: Muncul di layar dan membunyikan suara"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Selama %1$d menit (hingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Selama satu menit (hingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index b362bef..240c715 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Læsa núna"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
<string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persónulegt"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"stjórna titringi"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Leyfir forriti að stjórna titraranum."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"stjórna vasaljósi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Leyfir forriti að stjórna vasaljósinu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"hringja beint í símanúmer"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Leyfir forriti að hringja í símanúmer án íhlutunar notanda. Þetta getur haft í för með sér óumbeðin gjöld og símtöl. Athugaðu að þetta leyfir forritinu ekki að hringja í neyðarnúmer. Spilliforrit geta stofnað til kostnaðar fyrir þig með því að hringja símtöl án þinnar heimildar."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"fá aðgang að IMS-símtalsþjónustu"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Klippa"</string>
<string name="copy" msgid="2681946229533511987">"Afrita"</string>
<string name="paste" msgid="5629880836805036433">"Líma"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Líma sem ósniðinn texta"</string>
<string name="replace" msgid="5781686059063148930">"Skipta út…"</string>
<string name="delete" msgid="6098684844021697789">"Eyða"</string>
<string name="copyUrl" msgid="2538211579596067402">"Afrita vefslóð"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Velja texta"</string>
+ <string name="undo" msgid="7905788502491742328">"Afturkalla"</string>
+ <string name="redo" msgid="7759464876566803888">"Endurgera"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Textaval"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Bæta við orðabók"</string>
<string name="deleteText" msgid="6979668428458199034">"Eyða"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Skipta um veggfóður"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Tilkynningahlustun"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Skilyrðaveita"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Tilkynningaaðstoð"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN virkjað"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er virkjað með <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Snertu til að hafa umsjón með netinu."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Uppfært af kerfisstjóranum"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eytt af kerfisstjóra"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Útilokaðar: Aldrei sýna þessar tilkynningar"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Léttvægar: Sýna neðst á tilkynningalistanum án hljóðs"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Venjulegar: Sýna þessar tilkynningar án hljóðs"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Mikilvægar: Sýna efst á tilkynningalistanum og spila hljóð"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Áríðandi: Birta á skjánum og spila hljóð"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Í %1$d mínútu (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Í %1$d mínútur (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> valin</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Ýmislegt"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Þú stilltir mikilvægi þessara tilkynninga."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 66e7a2a..ece503d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocca ora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
<string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personale"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controllo vibrazione"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Consente all\'applicazione di controllare il flash."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Taglia"</string>
<string name="copy" msgid="2681946229533511987">"Copia"</string>
<string name="paste" msgid="5629880836805036433">"Incolla"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Incolla come testo normale"</string>
<string name="replace" msgid="5781686059063148930">"Sostituisci..."</string>
<string name="delete" msgid="6098684844021697789">"Elimina"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copia URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Seleziona testo"</string>
+ <string name="undo" msgid="7905788502491742328">"Annulla"</string>
+ <string name="redo" msgid="7759464876566803888">"Ripeti"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selezione testo"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Aggiungi al dizionario"</string>
<string name="deleteText" msgid="6979668428458199034">"Elimina"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener di notifica"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider condizioni"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente notifica"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN attiva"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN attivata da <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tocca per gestire la rete."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aggiornato dall\'amministratore"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminato dall\'amministratore"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di localizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloccato: non mostrare mai queste notifiche"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Bassa: mostra silenziosamente alla fine dell\'elenco di notifiche"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normale: mostra silenziosamente queste notifiche"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostra all\'inizio dell\'elenco di notifiche e riproduci suono"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: apri sullo schermo e riproduci suono"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Per %1$d minuti (fino alle ore <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Per un minuto (fino alle ore <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1479,8 +1475,8 @@
<item quantity="other">Per %d ore</item>
<item quantity="one">Per 1 ora</item>
</plurals>
- <string name="zen_mode_until" msgid="7336308492289875088">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino alle ore <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
+ <string name="zen_mode_until" msgid="7336308492289875088">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Fino a <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (prossima sveglia)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Fino alla disattivazione"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Fino alla disattivazione di Non disturbare"</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> elemento selezionato</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Vari"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Stabilisci tu l\'importanza di queste notifiche."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index b0c7437..144afc0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"נעל עכשיו"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
<string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
<string name="android_system_label" msgid="6577375335728551336">"מערכת Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"אישי"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"שליטה ברטט"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"מאפשר לאפליקציה לשלוט ברטט."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"מאפשר לאפליקציה לשלוט בפנס."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"גישה אל שירות שיחות IMS"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"חתוך"</string>
<string name="copy" msgid="2681946229533511987">"העתק"</string>
<string name="paste" msgid="5629880836805036433">"הדבק"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"הדבק כטקסט פשוט"</string>
<string name="replace" msgid="5781686059063148930">"החלף..."</string>
<string name="delete" msgid="6098684844021697789">"מחק"</string>
<string name="copyUrl" msgid="2538211579596067402">"העתק כתובת אתר"</string>
<string name="selectTextMode" msgid="1018691815143165326">"בחר טקסט"</string>
+ <string name="undo" msgid="7905788502491742328">"בטל"</string>
+ <string name="redo" msgid="7759464876566803888">"בצע מחדש"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"בחירת טקסט"</string>
<string name="addToDictionary" msgid="4352161534510057874">"הוסף למילון"</string>
<string name="deleteText" msgid="6979668428458199034">"מחק"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"שנה טפט"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"מאזין להתראות"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ספק תנאי"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"אסיסטנט ההודעות"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN מופעל"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN מופעל על ידי <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"גע כדי לנהל את הרשת."</string>
@@ -1458,12 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"עודכן על ידי מנהל המערכת שלך"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"נמחקה על ידי מנהל המערכת שלך"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם תפתח אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"חשיבות"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"חסימה: לעולם אל תציג הודעות אלה"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"נמוכה: הצג בתחתית רשימת ההודעות בלי להשמיע צליל"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"רגילה: הצג הודעות אלה בלי להשמיע צליל"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"גבוהה: הצג בראש רשימת ההודעות והשמע צליל"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"דחופה: הצג לרגע על המסך והשמע צליל"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="two">למשך %d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="many">למשך %1$d דקות (עד <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1547,6 +1544,6 @@
<item quantity="one">בחרת <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"שונות"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"אתה מגדיר את חשיבותן של הודעות אלה."</string>
+ <string name="importance_from_topic" msgid="3572280439880023233">"אתה מגדיר את החשיבות של ההודעות האלה."</string>
<string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 6b3e278..edfab22 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"今すぐロック"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 件)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
<string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
<string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人用"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"バイブレーションの制御をアプリに許可します。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ライトの制御をアプリに許可します。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"切り取り"</string>
<string name="copy" msgid="2681946229533511987">"コピー"</string>
<string name="paste" msgid="5629880836805036433">"貼り付け"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"書式なしテキストとして貼り付け"</string>
<string name="replace" msgid="5781686059063148930">"置換..."</string>
<string name="delete" msgid="6098684844021697789">"削除"</string>
<string name="copyUrl" msgid="2538211579596067402">"URLをコピー"</string>
<string name="selectTextMode" msgid="1018691815143165326">"テキストを選択"</string>
+ <string name="undo" msgid="7905788502491742328">"元に戻す"</string>
+ <string name="redo" msgid="7759464876566803888">"やり直し"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"テキスト選択"</string>
<string name="addToDictionary" msgid="4352161534510057874">"辞書に追加"</string>
<string name="deleteText" msgid="6979668428458199034">"削除"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"壁紙を変更"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知リスナー"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"コンディションプロバイダ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知アシスタント"</string>
<string name="vpn_title" msgid="19615213552042827">"VPNが有効になりました"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPNが<xliff:g id="APP">%s</xliff:g>により有効化されました"</string>
<string name="vpn_text" msgid="3011306607126450322">"タップしてネットワークを管理します。"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"管理者によって更新されています"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"管理者によって削除されました"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ブロック: 今後はこの通知を表示しない"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"低: 通知リストの下にマナーモードで表示する"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"標準: この通知をマナーモードで表示する"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"高: 通知リストの上に表示し、音声でも知らせる"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"緊急: 画面にプレビューを表示し、音声でも知らせる"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d分間(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>まで)</item>
<item quantity="one">1分間(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>まで)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>件選択済み</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"その他"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"このような通知の重要度を設定します。"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
</resources>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 38b2062..ffdd31c 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ახლა ჩაკეტვა"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
<string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
<string name="user_owner_label" msgid="2804351898001038951">"პირადი"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"პირდაპირი დარეკვა ტელეფონის ნომრებზე"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"აპს შეეძლება დარეკოს ტელეფონის ნომრებზე თქვენი ჩარევის გარეშე. ამან შესაძლოა გამოიწვიოს თქვენს სატელეფონი ქვითარზე მოულოდნელი ხარჯებისა და ზარების გაჩენა. გაითვალისწინეთ, რომ აპს გადაუდებელი დახმარების ნომრებზე დარეკვა არ შეუძლია. მავნე აპებს შეეძლება თქვენი დადასტურების გარეშე ზარების განხორციელება და შესაბამისი საფასურის გადახდაც მოგიწევთ."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ზარების სერვისზე წვდომა"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ამოჭრა"</string>
<string name="copy" msgid="2681946229533511987">"კოპირება"</string>
<string name="paste" msgid="5629880836805036433">"ჩასმა"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"ჩვეულებრივ ტექსტად ჩასმა"</string>
<string name="replace" msgid="5781686059063148930">"ჩანაცვლება…"</string>
<string name="delete" msgid="6098684844021697789">"წაშლა"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL კოპირება"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ტექსტის მონიშვნა"</string>
+ <string name="undo" msgid="7905788502491742328">"დაბრუნება"</string>
+ <string name="redo" msgid="7759464876566803888">"გამეორება"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ტექსტის მონიშვნა"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ლექსიკონში დამატება"</string>
<string name="deleteText" msgid="6979668428458199034">"წაშლა"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ფონის შეცვლა"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"შეტყობინებების მსმენელი"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"მდგომარეობის პროვაიდერი"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"შეტყობინებათა ასისტენტი"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN გააქტიურებულია"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN გააქტიურებულია <xliff:g id="APP">%s</xliff:g>-ის მიერ"</string>
<string name="vpn_text" msgid="3011306607126450322">"შეეხეთ ქსელის სამართავად."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"თქვენი ადმინისტრატორის მიერ წაშლილი"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ელემენტის მოქმედების ვადის გაუმჯობესებისათვის, ელემენტის დამზოგი ამცირებს თქვენი მოწყობილობის შესრულებას და ზღუდავს ვიბრაციას, ადგილმდებარეობის მომსახურებებს და ძირითად ფონურ მონაცემებს. ელ-ფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დაყრდნობილი აპლიკაციების განახლება არ მოხდება მათ გახსნეამდე. \n\n ელემენტის დამზოგველი ავტომატურად გამოირთვება, როდესაც თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"დაბლოკილი: ეს შეტყობინებები აღარასოდეს გამოჩნდება"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"დაბალი: ეს შეტყობინებები სიის ბოლოში, უხმოდ გამოჩნდება"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ნორმალური: ეს შეტყობინებები უხმოდ გამოჩნდება"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"მაღალი: ეს შეტყობინებები სიის თავში, ხმოვან სიგნალთან ერთად გამოჩნდება"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"გადაუდებელი: შეტყობინებები პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად გამოჩნდება"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>-მდე)</item>
<item quantity="one">ერთი წუთის განმავლობაში (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>-მდე)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> შერჩეული</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"სხვადასხვა"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრება თქვენ მიერ."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
</resources>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 6e26292..ff58eaa 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Қазір бекіту"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
<string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"тербелісті басқару"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Қолданбаға вибраторды басқаруға рұқсат береді."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"сигналдық шамды басқару"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Қолданбаға қалта шамын басқаруға рұқсат береді."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"нөмірлерге тікелей телефон шалу"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS қоңырау қызметін пайдалану"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Қиып алу"</string>
<string name="copy" msgid="2681946229533511987">"Көшіру"</string>
<string name="paste" msgid="5629880836805036433">"Қою"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Кәдімгі мәтін ретінде қою"</string>
<string name="replace" msgid="5781686059063148930">"… сөзін алмастыру"</string>
<string name="delete" msgid="6098684844021697789">"Жою"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL мекенжайын көшіру"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Мәтінді бөлектеу"</string>
+ <string name="undo" msgid="7905788502491742328">"Кері қайтару"</string>
+ <string name="redo" msgid="7759464876566803888">"Қайтару"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Мәтін таңдау"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Сөздікке қосу"</string>
<string name="deleteText" msgid="6979668428458199034">"Жою"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Артқы фонын өзгерту"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Хабар бақылағыш"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт провайдері"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Хабарландыру көмекшісі"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN белсенді"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"ВЖЭ <xliff:g id="APP">%s</xliff:g> арқылы қосылған"</string>
<string name="vpn_text" msgid="3011306607126450322">"Желіні басқару үшін түрту."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Әкімші жаңартты"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Әкімші жойған"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Батареяның қызмет көрсету мерзімін жақсарту үшін батарея үнемдегіш құрылғының өнімділігін төмендетеді және дірілді, орынды анықтау қызметтерін және фондық деректердің көпшілігін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nБатарея үнемдегіш құрылғы зарядталып жатқанда автоматты түрде өшеді."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Маңыздылық"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Бұғатталған: осы хабарландыруларды ешқашан көрсетпеу"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Төмен: хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Қалыпты: осы хабарландыруларды үнсіз көрсету"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Жоғары: хабарландырулар тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Шұғыл: экранға бекіту және дыбыс шығару"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d минут бойы (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> дейін)</item>
<item quantity="one">Бір минут бойы (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> дейін)</item>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 167fa17..261212f 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ចាក់សោឥឡូវនេះ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"បានលាក់មាតិកា"</string>
<string name="safeMode" msgid="2788228061547930246">"របៀបសុវត្ថិភាព"</string>
<string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ផ្ទាល់ខ្លួន"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យកម្មវិធីថតរូប និងវីដេអូដោយប្រើម៉ាស៊ីនថត។ វាឲ្យកម្មវិធីប្រើម៉ាស៊ីនថតនៅពេលណាមួយដោយគ្មានការបញ្ជាក់របស់អ្នក។"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ពិនិត្យការញ័រ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ឲ្យកម្មវិធីគ្រប់គ្រងកម្មវិធីញ័រ។"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ត្រួតពិនិត្យពិល"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ឲ្យកម្មវិធីពិនិត្យពិល។"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ហៅលេខទូរស័ព្ទដោយផ្ទាល់"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ឲ្យកម្មវិធីហៅលេខទូរស័ព្ទដោយគ្មានសកម្មភាពរបស់អ្នក។ វាអាចកាត់លុយ ឬហៅដោយមិនរំពឹងទុក។ ចំណាំថា វាមិនអនុញ្ញាតឲ្យកម្មវិធីហៅលេខពេលអាសន្នទេ។ កម្មវិធីព្យាបាទអាចកាត់លុយរបស់អ្នក ដោយធ្វើការហៅដោយគ្មានការបញ្ជាក់របស់អ្នក។"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"ចូលដំណើរការសេវាកម្មការហៅតាម IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"កាត់"</string>
<string name="copy" msgid="2681946229533511987">"ចម្លង"</string>
<string name="paste" msgid="5629880836805036433">"បិទភ្ជាប់"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"បិទភ្ជាប់ជាអត្ថបទធម្មតា"</string>
<string name="replace" msgid="5781686059063148930">"ជំនួស..."</string>
<string name="delete" msgid="6098684844021697789">"លុប"</string>
<string name="copyUrl" msgid="2538211579596067402">"ចម្លង URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ជ្រើសអត្ថបទ"</string>
+ <string name="undo" msgid="7905788502491742328">"មិនធ្វើវិញ"</string>
+ <string name="redo" msgid="7759464876566803888">"ធ្វើវិញ"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ការជ្រើសអត្ថបទ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"បន្ថែមទៅវចនានុក្រម"</string>
<string name="deleteText" msgid="6979668428458199034">"លុប"</string>
@@ -1109,6 +1111,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ប្ដូរផ្ទាំងរូបភាព"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"កម្មវិធីស្ដាប់ការជូនដំណឹង"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ក្រុមហ៊ុនផ្ដល់លក្ខខណ្ឌ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"ជំនួយការជូនដំណឹង"</string>
<string name="vpn_title" msgid="19615213552042827">"បានធ្វើឲ្យ VPN សកម្ម"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"បានធ្វើឲ្យ VPN សកម្មដោយ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"ប៉ះ ដើម្បីគ្រប់គ្រងបណ្ដាញ។"</string>
@@ -1442,12 +1445,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"បានធ្វើបច្ចុប្បន្នភាពដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"បានលុបដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ដើម្បីជួយឲ្យថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំសំចៃថាមពលថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតភាពញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយស្ទើរតែទាំងអស់។ ការផ្ញើសារអ៊ីម៉ែល និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មអាចនឹងមិនធ្វើបច្ចុប្បន្នភាពទេ លុះត្រាតែអ្នកបើកពួកវា។\n\nកម្មវិធីសន្សំសំចៃបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"សារៈសំខាន់"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"បានរារាំង៖ កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"កម្រិតទាប៖ បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ធម្មតា៖ បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"កម្រិតខ្ពស់៖ បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"បន្ទាន់៖ លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">រយៈពេល %1$d នាទី (រហូតដល់ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">រយៈពេលមួយនាទី (រហូតដល់ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 0ada13af..f083702 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -166,7 +166,7 @@
<string name="low_memory" product="tv" msgid="516619861191025923">"ಟಿವಿ ಸಂಗ್ರಹಣೆ ತುಂಬಿದೆ. ಸ್ಥಳವನ್ನು ಮುಕ್ತಗೊಳಿಸಲು ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಿ."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"ಫೋನ್ ಸಂಗ್ರಹಣೆ ತಂಬಿದೆ. ಸ್ಥಳವನ್ನು ಖಾಲಿಯಾಗಿಸಲು ಕೆಲವು ಫೈಲ್ಗಳನ್ನು ಅಳಿಸಿ."</string>
<string name="ssl_ca_cert_warning" msgid="5848402127455021714">"ನೆಟ್ವರ್ಕ್ ಅನ್ನು ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
- <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಜ್ಞಾತ ಮೂರನೇ ವ್ಯಕ್ತಿಯ ಪ್ರಕಾರ"</string>
+ <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"ಅಜ್ಞಾತ ಥರ್ಡ್ ಪಾರ್ಟಿಯ ಪ್ರಕಾರ"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ನಿರ್ವಾಹಕರಿಂದ"</string>
<string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g> ಪ್ರಕಾರ"</string>
<string name="work_profile_deleted" msgid="5005572078641980632">"ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಅಳಿಸಲಾಗಿದೆ"</string>
@@ -200,7 +200,7 @@
<string name="shutdown_confirm" product="default" msgid="649792175242821353">"ನಿಮ್ಮ ಫೋನ್ ಸ್ಥಗಿತಗೊಳ್ಳುತ್ತದೆ."</string>
<string name="shutdown_confirm_question" msgid="2906544768881136183">"ನೀವು ಸ್ಥಗಿತಗೊಳಿಸಲು ಬಯಸುವಿರಾ?"</string>
<string name="reboot_safemode_title" msgid="7054509914500140361">"ಸುರಕ್ಷಿತ ಮೋಡ್ಗೆ ರೀಬೂಟ್ ಮಾಡಿ"</string>
- <string name="reboot_safemode_confirm" msgid="55293944502784668">"ನೀವು ಸುರಕ್ಷತೆ ಮೋಡ್ಗೆ ರೀಬೂಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ? ಇದು ನೀವು ಸ್ಥಾಪಿಸಿರುವ ಎಲ್ಲಾ ಮೂರನೇ ವ್ಯಕ್ತಿಯ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ. ನೀವು ಮತ್ತೊಮ್ಮೆ ರೀಬೂಟ್ ಮಾಡಿದಾಗ ಅವುಗಳನ್ನು ಮರುಸ್ಥಾಪಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="reboot_safemode_confirm" msgid="55293944502784668">"ನೀವು ಸುರಕ್ಷತೆ ಮೋಡ್ಗೆ ರೀಬೂಟ್ ಮಾಡಲು ಬಯಸುವಿರಾ? ಇದು ನೀವು ಸ್ಥಾಪಿಸಿರುವ ಎಲ್ಲಾ ಥರ್ಡ್ ಪಾರ್ಟಿ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ. ನೀವು ಮತ್ತೊಮ್ಮೆ ರೀಬೂಟ್ ಮಾಡಿದಾಗ ಅವುಗಳನ್ನು ಮರುಸ್ಥಾಪಿಸಲಾಗುತ್ತದೆ."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"ಇತ್ತೀಚಿನದು"</string>
<string name="no_recent_tasks" msgid="8794906658732193473">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಲ್ಲ."</string>
<string name="global_actions" product="tablet" msgid="408477140088053665">"ಟ್ಯಾಬ್ಲೆಟ್ ಆಯ್ಕೆಗಳು"</string>
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ಈಗ ಲಾಕ್ ಮಾಡಿ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ವೈಯಕ್ತಿಕ"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ವೈಬ್ರೇಷನ್ ನಿಯಂತ್ರಿಸಿ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ವೈಬ್ರೇಟರ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ಫ್ಲ್ಯಾಶ್ಲೈಟ್ ನಿಯಂತ್ರಿಸಿ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ಫ್ಲ್ಯಾಶ್ಲೈಟ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ನಿಮ್ಮ ಹಸ್ತಕ್ಷೇಪ ಇಲ್ಲದೆಯೇ ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಅನಿರೀಕ್ಷಿತ ಶುಲ್ಕಗಳು ಅಥವಾ ಕರೆಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ತುರ್ತು ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆಮಾಡಲು ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನುಮತಿಸುವುದಿಲ್ಲ ಎಂಬುದು ಗಮನದಲ್ಲಿರಲಿ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್ಗಳು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡುವುದರ ಮೂಲಕ ನಿಮ್ಮ ಹಣ ಖರ್ಚಾಗಬಹುದು."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ಕರೆ ಸೇವೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ಕತ್ತರಿಸು"</string>
<string name="copy" msgid="2681946229533511987">"ನಕಲಿಸು"</string>
<string name="paste" msgid="5629880836805036433">"ಅಂಟಿಸಿ"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"ಸರಳ ಪಠ್ಯದಂತೆ ಅಂಟಿಸು"</string>
<string name="replace" msgid="5781686059063148930">"ಸ್ಥಾನಾಂತರಿಸು..."</string>
<string name="delete" msgid="6098684844021697789">"ಅಳಿಸು"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL ನಕಲಿಸು"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ಪಠ್ಯವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="undo" msgid="7905788502491742328">"ರದ್ದುಗೊಳಿಸಿ"</string>
+ <string name="redo" msgid="7759464876566803888">"ಪುನಃ ಮಾಡು"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ಪಠ್ಯದ ಆಯ್ಕೆ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ನಿಘಂಟಿಗೆ ಸೇರಿಸಿ"</string>
<string name="deleteText" msgid="6979668428458199034">"ಅಳಿಸು"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ವಾಲ್ಪೇಪರ್ ಬದಲಿಸಿ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ಅಧಿಸೂಚನೆ ಕೇಳುಗ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ಕಂಡೀಶನ್ ಪೂರೈಕೆದಾರರು"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"ಅಧಿಸೂಚನೆ ಸಹಾಯಕ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ಮೂಲಕ VPN ಸಕ್ರಿಯಗೊಂಡಿದೆ"</string>
<string name="vpn_text" msgid="3011306607126450322">"ನೆಟ್ವರ್ಕ್ ನಿರ್ವಹಿಸಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ನವೀಕರಿಸಲಾಗಿದೆ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಳಿಸಲಾಗಿದೆ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ನಿಮ್ಮ ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವುದನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ, ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ನವೀಕರಣಗೊಳ್ಳುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"ಕಡಿಮೆ: ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ಸಾಮಾನ್ಯ: ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ಅಧಿಕ: ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ತುರ್ತು: ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
<item quantity="other">%1$d ನಿಮಿಷಗಳವರೆಗೆ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ವರೆಗೆ)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"ಇತರೆ"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index e15df94..c8f08c7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"지금 잠그기"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>개)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
<string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
<string name="user_owner_label" msgid="2804351898001038951">"개인"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"진동 제어"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"앱이 진동을 제어할 수 있도록 허용합니다."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"앱이 카메라 플래시를 제어할 수 있도록 허용합니다."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"앱이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 허용합니다. 이 경우 예상치 못한 통화 요금이 부과될 수 있습니다. 앱이 비상 전화를 걸도록 하는 권한은 주어지지 않습니다. 악성 앱이 사용자의 확인 없이 전화를 걸어 요금이 부과될 수 있습니다."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS 통화 서비스에 액세스"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"잘라내기"</string>
<string name="copy" msgid="2681946229533511987">"복사"</string>
<string name="paste" msgid="5629880836805036433">"붙여넣기"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"일반 텍스트로 붙여넣기"</string>
<string name="replace" msgid="5781686059063148930">"바꾸기..."</string>
<string name="delete" msgid="6098684844021697789">"삭제"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL 복사"</string>
<string name="selectTextMode" msgid="1018691815143165326">"텍스트 선택"</string>
+ <string name="undo" msgid="7905788502491742328">"실행취소"</string>
+ <string name="redo" msgid="7759464876566803888">"다시 실행"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"텍스트 선택"</string>
<string name="addToDictionary" msgid="4352161534510057874">"사전에 추가"</string>
<string name="deleteText" msgid="6979668428458199034">"삭제"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"배경화면 변경"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"알림 수신기"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"조건 제공자"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"알림 어시스턴트"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN이 활성화됨"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN이 <xliff:g id="APP">%s</xliff:g>에 의해 활성화됨"</string>
<string name="vpn_text" msgid="3011306607126450322">"네트워크를 관리하려면 터치하세요."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"관리자에 의해 업데이트됨"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"관리자가 삭제함"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"배터리 수명 개선을 위해, 배터리 세이버는 기기의 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기를 충전 중일 때는 자동으로 사용 중지됩니다."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"차단: 알림 다시 표시 안함"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"낮음: 알림 목록 하단에 무음으로 표시"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"일반: 무음으로 알림 표시"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"높음: 알림 목록 상단에 표시하고 소리로 알림"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"긴급: 화면에 표시하고 소리로 알림"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d분 동안(<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>까지)</item>
<item quantity="one">1분 동안(<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>까지)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>개 선택됨</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"기타"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"이러한 알림의 중요도를 설정했습니다."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
</resources>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index af81c88..4d84933 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Азыр кулпулоо"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
<string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Тутуму"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Жеке"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"титирөөнү башкаруу"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"кол чыракты көзөмөлдөө"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Колдонмого колчыракты көзөмөлдөө мүмкүнчүлүгүн берет."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"телефон номерлерине түз чалуу"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string>
@@ -859,10 +858,13 @@
<string name="cut" msgid="3092569408438626261">"Кесүү"</string>
<string name="copy" msgid="2681946229533511987">"Көчүрүү"</string>
<string name="paste" msgid="5629880836805036433">"Чаптоо"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Жөнөкөй текст катары чаптоо"</string>
<string name="replace" msgid="5781686059063148930">"Алмаштыруу…"</string>
<string name="delete" msgid="6098684844021697789">"Жок кылуу"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL көчүрмөлөө"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Текст тандоо"</string>
+ <string name="undo" msgid="7905788502491742328">"Артка кайтаруу"</string>
+ <string name="redo" msgid="7759464876566803888">"Кайталоо"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Текст тандоо"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Сөздүккө кошуу"</string>
<string name="deleteText" msgid="6979668428458199034">"Жок кылуу"</string>
@@ -1108,6 +1110,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Тушкагазды өзгөртүү"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Эскертүү тыңшагычы"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Шарт түзүүчү"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Эскертме жардамчысы"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN иштетилди"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> аркылуу жандырылды"</string>
<string name="vpn_text" msgid="3011306607126450322">"желени башкаруу үчүн басыңыз."</string>
@@ -1441,13 +1444,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Администраторуңуз тарабынан жок кылынган"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Батареянын өмүрүн узартуу үчүн, батареяны үнөмдөгүч түзмөгүңүздүн ишинин майнаптуулугун азайтып, дирилдөө, жайгашкан жерди аныктоо кызматтары жана фондук дайындардын көпчүлүгүн чектеп коёт. Электрондук почта, билдирүү жазышуу жана башка шайкештештирүүгө байланыштуу колдонмолор ачылмайынча жаңыртылбай калышы мүмкүн.\n\nБатарея үнөмдөгүч түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Бөгөттөлгөн: Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Төмөн: Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Кадимки: Бул эскертмелер үнсүз көрсөтүлсүн"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Жогору: Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Шашылыш: Үн менен коштолуп, экранга чыгарылсын"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d мүнөткө (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> чейин)</item>
<item quantity="one">Бир мүнөткө (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> чейин)</item>
@@ -1513,8 +1509,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> тандалды</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Калган-каткандар"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
</resources>
diff --git a/core/res/res/values-land/config.xml b/core/res/res/values-land/config.xml
new file mode 100644
index 0000000..7308dc5
--- /dev/null
+++ b/core/res/res/values-land/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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>
+ <integer name="config_dockedStackDividerSnapMode">2</integer>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 723a28a..12d67bb 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ລັອກດຽວນີ້"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາຖືກເຊື່ອງໄວ້"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ສ່ວນໂຕ"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ຄວບຄຸມການສັ່ນ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ຄວບຄຸມໄຟແຟລດ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມໄຟແຟລດ."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ໂທຫາເບີໂທລະສັບໂດຍກົງ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ອະນຸຍາດໃຫ້ແອັບຯໂທຫາເບີໂທລະສັບໄດ້ ໂດຍບໍ່ຕ້ອງຖ້າການດຳເນີນການໃດໆຈາກທ່ານ. ຄຸນສົມບັດນີ້ອາດກໍ່ໃຫ້ເກີດຄ່າໃຊ້ຈ່າຍໃນການໂທທີ່ບໍ່ຄາດຄິດໄດ້. ໝາຍເຫດ: ຄຸນສົມບັດນີ້ບໍ່ໄດ້ເປັນການອະນຸຍາດໃຫ້ແອັບຯ ສາມາດໂທຫາເບີສຸກເສີນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເຮັດໃຫ້ທ່ານ ຕ້ອງເສຍຄ່າໂທໂດຍທີ່ບໍ່ໄດ້ຄາດຄິດ."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"ເຂົ້າຫາການບໍລິການໂທ IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ຕັດ"</string>
<string name="copy" msgid="2681946229533511987">"ສຳເນົາ"</string>
<string name="paste" msgid="5629880836805036433">"ວາງ"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"ວາງເປັນຂໍ້ຄວາມທຳມະດາ"</string>
<string name="replace" msgid="5781686059063148930">"ແທນທີ່…"</string>
<string name="delete" msgid="6098684844021697789">"ລຶບ"</string>
<string name="copyUrl" msgid="2538211579596067402">"ສຳເນົາ URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ເລືອກຂໍ້ຄວາມ"</string>
+ <string name="undo" msgid="7905788502491742328">"ບໍ່ເຮັດ"</string>
+ <string name="redo" msgid="7759464876566803888">"ເຮັດໃໝ່"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ການເລືອກຂໍ້ຄວາມ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ເພີ່ມໄປທີ່ວັດຈະນານຸກົມ"</string>
<string name="deleteText" msgid="6979668428458199034">"ລຶບ"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ປ່ຽນພາບພື້ນຫຼັງ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ໂຕຟັງການແຈ້ງເຕືອນ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ຜູ່ສະໜອງເງື່ອນໄຂ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"ຕົວຊ່ວຍການແຈ້ງເຕືອນ"</string>
<string name="vpn_title" msgid="19615213552042827">"ເປີດນຳໃຊ້ VPN ແລ້ວ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"ເປີດໃຊ້ VPN ໂດຍ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"ແຕະເພື່ອຈັດການເຄືອຂ່າຍ."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"ອັບເດດໂດຍຜູ້ຄວບຄຸມຂອງທ່ານແລ້ວ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"ຖືກຜູ້ຄວບຄຸມຂອງທ່ານລຶບໄປແລ້ວ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ເພື່ອຊ່ວຍເພີ່ມອາຍຸແບັດເຕີຣີ, ຕົວປະຢັດໄຟແບັດເຕີຣີຫຼຸດປະສິດທິພາບການເຮັດວຽກຂອງອຸປະກອນຂອງທ່ານລົງ ແລະຈຳກັດການສັ່ນ, ການບໍລິການຫາທີ່ຕັ້ງ, ແລະຂໍ້ມູນພື້ນຫຼັງເກືອບທັງໝົດ. ອີເມວ, ການສົ່ງຂໍ້ຄວາມ, ແລະແອັບອື່ນໆທີ່ອາໄສການຊິງຄ໌ອາດຈະບໍ່ອັບເດດ ນອກຈາກວ່າທ່ານເປີດມັນ.\n\nຕົວປະຢັດໄຟແບັດເຕີຣີຈະປິດອັດຕະໂນມັດ ເມື່ອອຸປະກອນຂອງທ່ານກຳລັງສາກຢູ່."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ບລັອກແລ້ວ: ຢ່າສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"ຕໍ່າ: ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ປົກກະຕິ: ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ສູງ: ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ດ່ວນ: ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">ເປັນເວລາ %1$d ນາທີ (ຈົນຮອດ <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">ເປັນເວລາ 1 ນາທີ (ຈົນຮອດ <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ຖືກເລືອກແລ້ວ</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"ອື່ນໆ"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 67eff63..e35edd6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Užrakinti dabar"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
<string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
<string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Asmeninė"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"valdyti vibraciją"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Leidžiama programai valdyti vibravimą."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Leidžiama programai valdyti šviesos signalą."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Leidžiama programai skambinti telefonų numeriais be jūsų įsikišimo. Dėl to gali atsirasti nenumatytų apmokestinimų ar skambučių. Atminkite, kad programai neleidžiama skambinti pagalbos telefonų numeriais. Kenkėjiškos programos gali skambinti be jūsų patvirtinimo, o dėl to jums gali būti taikomi mokesčiai."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"pasiekti IMS skambučių paslaugą"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Iškirpti"</string>
<string name="copy" msgid="2681946229533511987">"Kopijuoti"</string>
<string name="paste" msgid="5629880836805036433">"Įklijuoti"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Įklijuoti kaip grynąjį tekstą"</string>
<string name="replace" msgid="5781686059063148930">"Pakeisti•"</string>
<string name="delete" msgid="6098684844021697789">"Ištrinti"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopijuoti URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Pasirinkti tekstą"</string>
+ <string name="undo" msgid="7905788502491742328">"Anuliuoti"</string>
+ <string name="redo" msgid="7759464876566803888">"Grąžinti"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksto pasirinkimas"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Pridėti prie žodyno"</string>
<string name="deleteText" msgid="6979668428458199034">"Ištrinti"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Keisti darbalaukio foną"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pranešimų skaitymo priemonė"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Sąlygos teikėjas"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pranešimų pagelbiklis"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN suaktyvintas"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN suaktyvino „<xliff:g id="APP">%s</xliff:g>“"</string>
<string name="vpn_text" msgid="3011306607126450322">"Palieskite, kad valdytumėte tinklą."</string>
@@ -1458,12 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atnaujino administratorius"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Ištrynė administratorius"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Svarba"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Užblokuota: niekada nerodyti šių pranešimų"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Maža: tyliai rodyti pranešimų sąrašo apačioje"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Įprasta: tyliai rodyti šiuos pranešimus"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Didelė: rodyti pranešimų sąrašo viršuje ir skambėti"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Skubu: rodyti ekrane ir skambėti"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d minutę (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d minutes (iki <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 8c87e00..de02a4f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -224,6 +224,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloķēt tūlīt"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"Pārsniedz"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
<string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personisks"</string>
@@ -354,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrolēt vibrosignālu"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ļauj lietotnei kontrolēt vibrosignālu."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ļauj lietotnei kontrolēt zibspuldzi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ļauj lietotnei zvanīt uz tālruņa numuriem bez jūsu iejaukšanās. Tas var radīt neparedzētas izmaksas vai zvanus. Ņemiet vērā, ka lietotnei nav atļauts zvanīt uz tālruņa numuriem ārkārtas situācijām. Ļaunprātīgas lietotnes var radīt jums izmaksas, veicot zvanus bez jūsu apstiprinājuma."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"piekļūt tūlītējās ziņojumapmaiņas pakalpojumam, lai veiktu zvanus"</string>
@@ -863,10 +862,13 @@
<string name="cut" msgid="3092569408438626261">"Izgriezt"</string>
<string name="copy" msgid="2681946229533511987">"Kopēt"</string>
<string name="paste" msgid="5629880836805036433">"Ielīmēt"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Ielīmēt kā vienkāršu tekstu"</string>
<string name="replace" msgid="5781686059063148930">"Aizstāt"</string>
<string name="delete" msgid="6098684844021697789">"Dzēst"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopēt URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Atlasīt tekstu"</string>
+ <string name="undo" msgid="7905788502491742328">"Atsaukt"</string>
+ <string name="redo" msgid="7759464876566803888">"Atcelt atsaukšanu"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Teksta atlase"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Pievienot vārdnīcai"</string>
<string name="deleteText" msgid="6979668428458199034">"Dzēst"</string>
@@ -1114,6 +1116,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tapetes maiņa"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Paziņojumu uztvērējs"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nosacījumu sniedzējs"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Paziņojumu palīgs"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ir aktivizēts."</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Lietojumprogramma <xliff:g id="APP">%s</xliff:g> aktivizēja VPN."</string>
<string name="vpn_text" msgid="3011306607126450322">"Pieskarieties, lai pārvaldītu tīklu."</string>
@@ -1449,13 +1452,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Izdzēsa jūsu administrators"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloķēts: nekad nerādīt šos paziņojumus"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Zemu: rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normāli: rādīt šos paziņojumus bez skaņas signāla"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Augstu: rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Steidzami: rādīt ekrānā ar skaņas signālu"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="zero">%1$d minūtes (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">%1$d minūti (līdz <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1530,8 +1526,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> atlasīti</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Dažādi"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
</resources>
diff --git a/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml b/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..6750940
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-b+sr+Latn/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="wfcOperatorErrorAlertMessages">
+ <item msgid="7239039348648848288">"Da biste upućivali pozive i slali poruke preko Wi-Fi-ja, prvo zatražite od mobilnog operatera da vam omogući ovu uslugu. Zatim u Podešavanjima ponovo uključite Pozivanje preko Wi-Fi-ja."</item>
+ </string-array>
+ <string-array name="wfcOperatorErrorNotificationMessages">
+ <item msgid="483847327467331298">"Registrujte se kod mobilnog operatera"</item>
+ </string-array>
+ <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi pozivanje preko operatera %s"</string>
+</resources>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 124d7d6..96a29a5 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Заклучи сега"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролирај вибрации"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволува апликацијата да ги контролира вибрациите."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контролирај сијаличка"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволува апликацијата да ја контролира батериската ламба."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно избирај телефонски броеви"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Овозможува апликацијата да повикува телефонски броеви без ваша интервенција. Ова може да предизвика неочекувани трошоци или повици. Имајте на ум дека ова не дозволува апликацијата да повикува броеви на служби за итна помош. Злонамерните апликации може да ве чинат пари поради повици без ваша потврда."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"пристапи до услугата за повици IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Исечи"</string>
<string name="copy" msgid="2681946229533511987">"Копирај"</string>
<string name="paste" msgid="5629880836805036433">"Залепи"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Залепи како обичен текст"</string>
<string name="replace" msgid="5781686059063148930">"Замени..."</string>
<string name="delete" msgid="6098684844021697789">"Избриши"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копирај УРЛ"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Избери текст"</string>
+ <string name="undo" msgid="7905788502491742328">"Врати"</string>
+ <string name="redo" msgid="7759464876566803888">"Повтори"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Избор на текст"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Додај во речник"</string>
<string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промени тапет"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Слушател на известувања"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Давател на услов"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помошник за известувања"</string>
<string name="vpn_title" msgid="19615213552042827">"Активирана VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN е активирана со <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Допри за да управуваш со мрежата."</string>
@@ -1250,7 +1253,7 @@
<string name="media_route_chooser_title" msgid="1751618554539087622">"Поврзи се со уред"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"Префрли екран на уред"</string>
<string name="media_route_chooser_searching" msgid="4776236202610828706">"Пребарување за уреди..."</string>
- <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Подесувања"</string>
+ <string name="media_route_chooser_extended_settings" msgid="87015534236701604">"Поставки"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"Исклучи"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"Скенирање..."</string>
<string name="media_route_status_connecting" msgid="6422571716007825440">"Се поврзува..."</string>
@@ -1442,13 +1445,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирано од администраторот"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Избришано од администраторот"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и го ограничува вибрирањето, услугите за локација и повеќето податоци од заднина. Е-поштата, испраќањето пораки и другите апликации кои се потпираат на синхронизација можеби нема да се ажурираат доколку не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирано: никогаш не покажувај ги овие известувања"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Ниско: покажувај ги тивко на дното на списокот со известувања"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Нормално: покажувај ги овие известувања тивко"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Високо: покажувај ги на врв на списокот со известувања и дај звук"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Итно: нека се појават на екранот и дај им звук"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">За %1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">За %1$d минути (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1514,8 +1510,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> се избрани</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ја поставивте важноста на известувањава."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
</resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 842ee4a..f6869e3 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ഇപ്പോൾ ലോക്കുചെയ്യുക"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്റ്റുകൾ മറച്ചു"</string>
<string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
<string name="user_owner_label" msgid="2804351898001038951">"വ്യക്തിഗതം"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ടോർച്ച് നിയന്ത്രിക്കുക"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ഫ്ലാഷ്ലൈറ്റിനെ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"മുറിക്കുക"</string>
<string name="copy" msgid="2681946229533511987">"പകര്ത്തുക"</string>
<string name="paste" msgid="5629880836805036433">"ഒട്ടിക്കുക"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"പ്ലെയിൻ ടെക്സ്റ്റായി ഒട്ടിക്കുക"</string>
<string name="replace" msgid="5781686059063148930">"മാറ്റിസ്ഥാപിക്കുക..."</string>
<string name="delete" msgid="6098684844021697789">"ഇല്ലാതാക്കുക"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL പകർത്തുക"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ടെക്സ്റ്റ് തിരഞ്ഞെടുക്കുക"</string>
+ <string name="undo" msgid="7905788502491742328">"പഴയപടിയാക്കുക"</string>
+ <string name="redo" msgid="7759464876566803888">"വീണ്ടും ചെയ്യുക"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ടെക്സ്റ്റ് തിരഞ്ഞെടുക്കൽ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"നിഘണ്ടുവിൽ ചേർക്കുക"</string>
<string name="deleteText" msgid="6979668428458199034">"ഇല്ലാതാക്കുക"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"വാൾപേപ്പർ മാറ്റുക"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"അറിയിപ്പ് ലിസണർ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"കണ്ടീഷൻ ദാതാവ്"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"അറിയിപ്പ് സഹായി"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN സജീവമാക്കി"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ഉപയോഗിച്ച് VPN പ്രവർത്തനക്ഷമമാക്കി"</string>
<string name="vpn_text" msgid="3011306607126450322">"നെറ്റ്വർക്ക് നിയന്ത്രിക്കാൻ സ്പർശിക്കുക."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്റർ അപ്ഡേറ്റുചെയ്തു"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"നിങ്ങളുടെ അഡ്മിനിസ്ട്രേറ്റർ ഇല്ലാതാക്കി"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി സേവർ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്ക്കുകയും വൈബ്രേഷനെയും മിക്ക പശ്ചാത്തല വിവരത്തെയും പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. ഇമെയിൽ, സന്ദേശമയയ്ക്കൽ, സമന്വയിപ്പിക്കലിനെ ആശ്രയിച്ചുള്ള മറ്റ് അപ്ലിക്കേഷനുകൾ എന്നിവ നിങ്ങൾ തുറക്കുന്നതുവരെ അപ്ഡേറ്റുചെയ്യാനിടയില്ല.\n\nനിങ്ങളുടെ ഉപകരണം ചാർജ്ജുചെയ്യുമ്പോൾ ബാറ്ററി സേവർ സ്വയം ഓഫാകും."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"പ്രാധാന്യം"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ബ്ലോക്കുചെയ്തു: ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"താഴ്ന്നത്: അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"സാധാരണം: ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ഉയർന്നത്: അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"അടിയന്തരം: സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d മിനിറ്റ് സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> വരെ)</item>
<item quantity="one">ഒരു മിനിറ്റ് സമയത്തേക്ക് (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> വരെ)</item>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index d989270..d982ece 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Одоо түгжих"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
<string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Хувийн"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"чичиргээг удирдах"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Апп нь чичиргээг удирдах боломжтой."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"гар чийдэн удирдах"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Апп нь гар чийдэнг удирдах боломжтой."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"утасны дугаарт шууд дуудлага хийх"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Апп нь таны оролцоогүйгээр дуудлага хийх боломжтой. Энэ нь төлөвлөгдөөгүй төлбөрт оруулах эсвэл дуудлага хийнэ. Энэ нь апп-г яаралтай дугаарт дуудлага хийхйг зөвшөөрөхгүй. Хортой апп нь таны зөвшөөрөлгүйгээр дуудлага хийж таныг төлбөрт оруулж болзошгүй"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS дуудлагын үйлчилгээнд хандах"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Таслах"</string>
<string name="copy" msgid="2681946229533511987">"Хуулах"</string>
<string name="paste" msgid="5629880836805036433">"Буулгах"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Хоосон текст хэлбэрээр буулгах"</string>
<string name="replace" msgid="5781686059063148930">"Орлуулах…"</string>
<string name="delete" msgid="6098684844021697789">"Устгах"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL хуулах"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Текст сонгох"</string>
+ <string name="undo" msgid="7905788502491742328">"Буцаах"</string>
+ <string name="redo" msgid="7759464876566803888">"Дахин хийх"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Текст сонгох"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Толь бичигт нэмэх"</string>
<string name="deleteText" msgid="6979668428458199034">"Устгах"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ханын зураг солих"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Мэдэгдэл сонсогч"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Нөхцөл нийлүүлэгч"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Мэдэгдлийн туслагч"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN идэвхтэй болов"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-г <xliff:g id="APP">%s</xliff:g> идэвхтэй болгов"</string>
<string name="vpn_text" msgid="3011306607126450322">"Сүлжээг удирдах бол хүрнэ үү."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Танай админ шинэчилсэн"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Таны админ устгасан байна"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Батарей хадгалах функц нь таны төхөөрөмжийн цэнэгийг хадгалахын тулд гүйцэтгэлийг багасгаж, чичрэлтийг бууруулж, байршлын үйлчилгээнүүд болон бусад өгөгдлийн хэмжээг багасгадаг юм. И-мэйл, мессеж болон бусад синхрон хийдэг апликейшнүүд дараа дахин нээгдэх хүртлээ автоматаар шинэчлэлт хийхгүй.\n\nМөн батарей хадгалах функц нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтрах юм."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Блоклосон: Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Бага: Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Ердийн: Эдгээр мэдэгдлийг дуугүй харуулах"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Өндөр: мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Яаралтай: Дэлгэцэнд яаралтай, дуутай гаргах"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other"> %1$d минутын турш ( <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> хүртэл)</item>
<item quantity="one">нэг минутын турш (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> хүртэл)</item>
@@ -1510,8 +1506,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> сонгосон</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Бусад"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
</resources>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index c323b85..4087199 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"आता लॉक करा"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android सिस्टम"</string>
<string name="user_owner_label" msgid="2804351898001038951">"वैयक्तिक"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करा"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ्लॅशलाइट नियंत्रित करा"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्लॅशलाइट नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"आपल्या हस्तक्षेपाशिवाय फोन नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देते. यामुळे अनपेक्षित शुल्क किंवा कॉल लागू शकतात. लक्षात ठेवा की हे आणीबाणीच्या नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देत नाही. दुर्भावनापूर्ण अॅप्स नी आपल्या पुष्टिकरणाशिवाय कॉल केल्यामुळे आपले पैसे खर्च होऊ शकतात."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्ये प्रवेश करा"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"कट करा"</string>
<string name="copy" msgid="2681946229533511987">"कॉपी करा"</string>
<string name="paste" msgid="5629880836805036433">"पेस्ट करा"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"साधा मजकूर म्हणून पेस्ट करा"</string>
<string name="replace" msgid="5781686059063148930">"पुनर्स्थित करा…"</string>
<string name="delete" msgid="6098684844021697789">"हटवा"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL कॉपी करा"</string>
<string name="selectTextMode" msgid="1018691815143165326">"मजकूर निवडा"</string>
+ <string name="undo" msgid="7905788502491742328">"पूर्ववत करा"</string>
+ <string name="redo" msgid="7759464876566803888">"पुन्हा करा"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"मजकूर निवड"</string>
<string name="addToDictionary" msgid="4352161534510057874">"शब्दकोशात जोडा"</string>
<string name="deleteText" msgid="6979668428458199034">"हटवा"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदला"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना ऐकणारा"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"अट प्रदाता"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहाय्यक"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> द्वारे VPN सक्रिय केले आहे"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क व्यवस्थापित करण्यासाठी स्पर्श करा."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"आपल्या प्रशासकाद्वारे अद्यतनित केले"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"आपल्या प्रशासकाद्वारे हटविले आहे"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"बॅटरीचे आयुष्य सुधारित करण्यात मदत करण्यासाठी, बॅटरी बचतकर्ता आपल्या डिव्हाइसचे कार्यप्रदर्शन कमी करतो आणि कंपन, स्थान सेवा आणि बराच पार्श्वभूमी डेटा मर्यादित करतो. संकालनावर अवलंबून असणारे ईमेल, संदेशन आणि इतर अॅप्स आपण उघडल्याशिवाय अद्यतनित होऊ शकत नाहीत.\n\nआपले डिव्हाइस चार्ज होत असते तेव्हा बॅटरी बचतकर्ता स्वयंचलितपणे बंद होतो."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"अवरोधित केले: या सूचना कधीही दर्शवू नका"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"कमी: शांतपणे सूचना सूचीच्या तळाशी दर्शवा"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: या सूचना शांतपणे दर्शवा"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"सर्वोच्च: सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"त्वरित: स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d मिनिटासाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
<item quantity="other">%1$d मिनिटांसाठी (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> पर्यंत)</item>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 1993819..0923e91 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Kunci sekarang"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Peribadi"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kawal getaran"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Membenarkan apl mengawal penggetar."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"mengawal lampu suluh"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Membenarkan apl mengawal lampu suluh."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"panggil terus nombor telefon"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Membenarkan apl memanggil nombor telefon tanpa campur tangan anda. Ini mungkin menyebabkan caj atau panggilan yang di luar jangkaan. Apl hasad boleh menyebabkan anda kerugian wang dengan membuat panggilan tanpa pengesahan anda."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses perkhidmatan panggilan IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Potong"</string>
<string name="copy" msgid="2681946229533511987">"Salin"</string>
<string name="paste" msgid="5629880836805036433">"Tampal"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Tampal sebagai teks biasa"</string>
<string name="replace" msgid="5781686059063148930">"Ganti..."</string>
<string name="delete" msgid="6098684844021697789">"Padam"</string>
<string name="copyUrl" msgid="2538211579596067402">"Salin URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Pilih teks"</string>
+ <string name="undo" msgid="7905788502491742328">"Buat asal"</string>
+ <string name="redo" msgid="7759464876566803888">"Buat semula"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Pemilihan teks"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Tambah ke kamus"</string>
<string name="deleteText" msgid="6979668428458199034">"Padam"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Tukar kertas dinding"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Pendengar pemberitahuan"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Pembekal keadaan"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pembantu pemberitahuan"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Sentuh untuk mengurus rangkaian."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Dipadamkan oleh pentadbir anda"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan mengehadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Disekat: Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Rendah: Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Biasa: Tunjukkan pemberitahuan ini secara senyap"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Tinggi: Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Segera: Intai pada skrin dan bunyikan"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Selama %1$d minit (sehingga <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Selama satu minit (sehingga <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dipilih</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Pelbagai"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Anda menetapkan kepentingan pemberitahuan ini."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
</resources>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index e8178e3..3ef7e6c 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ယခု သော့ပိတ်ရန်"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"၉၉၉+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
<string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ကိုယ်ရေး"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"appအား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ဓါတ်မီးအား ထိန်းသိမ်းရန်"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"appအား ကား ဖလက်ရှမီးကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"အပလီကေးရှင်းအား အလိုအလျောက် ဖုန်းခေါ်ခွင့် ပြုပါ။ မလိုအပ်သော ဖုန်းခ များ ဖြစ်ပေါ်နိုင်ပါသည်။ ဒီခွင့်ပြုခြင်းမှာ အရေးပေါ်ဖုန်းခေါ်ခြင်း မပါဝင်ပါ။ သံသယဖြစ်စရာ အပလီကေးရှင်းများက သင့်မသိပဲ ဖုန်းခေါ်ခြင်းဖြင့် ဖုန်းခ ပိုမိုကျနိုင်ပါသည်။"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ဖုန်းခေါ်ဆိုမှု ဝန်ဆောင်ဌာန ဝင်ကြည့်ပါ"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ဖြတ်ခြင်း"</string>
<string name="copy" msgid="2681946229533511987">"ကူးခြင်း"</string>
<string name="paste" msgid="5629880836805036433">"Paste"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"စာသားအတိုင်း ကူးထည့်ပါ"</string>
<string name="replace" msgid="5781686059063148930">"အစားထိုခြင်း"</string>
<string name="delete" msgid="6098684844021697789">"ဖျက်ပစ်ရန်"</string>
<string name="copyUrl" msgid="2538211579596067402">"URLအား ကူးခြင်း"</string>
<string name="selectTextMode" msgid="1018691815143165326">"စာသား ရွေးရန်"</string>
+ <string name="undo" msgid="7905788502491742328">"ပြန်ဖျက်ရန်"</string>
+ <string name="redo" msgid="7759464876566803888">"ထပ်လုပ်ပါ"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"စာတိုရွေးချယ်မှု"</string>
<string name="addToDictionary" msgid="4352161534510057874">"အဘိဓာန်ထဲ ထည့်ပါ"</string>
<string name="deleteText" msgid="6979668428458199034">"ဖျက်ပစ်ရန်"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"နောက်ခံပြောင်းခြင်း"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"အကြောင်းကြားချက် နားတောင်သူ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"အခြေအနေ စီမံပေးသူ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"သတိပေးချက် အကူ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ဖွင့်ထားပါသည်"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>မှVPNအလုပ်လုပ်နေသည်"</string>
<string name="vpn_text" msgid="3011306607126450322">"ကွန်ရက် ထိန်းသိမ်းရန် တို့ထိပါ"</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"သင့်စီမံခန့်ခွဲသူမှ အဆင့်မြှင့်ထားပါသည်။"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"သင့် အက်ဒမင်အား ဖျက်ပစ်ရန်"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ဘက်ထရီသက်တမ်း ကြာရှည်ခံရန်၊ ဘက်ထရီအားထိန်းသည် သင့်ကိရိယာ၏ ဆောင်ရွက်ချက်ကို လျှော့ပေးပြီး တုန်ခါမှု၊ တည်နေရာဝန်ဆောင်မှုများနှင့်၊ နောက်ခံဒေတာအများစုကို ကန့်သတ်ပေး၏။ စင့်လုပ်ပေးရလေ့ရှိသည့် အီးမေး၊ စာပို့ခြင်းနှင့်၊ အခြားအပလီကေးရှင်းများကို ၎င်းတို့အား သင် ဖွင့်မှသာ အဆင့်မြှင့်မွမ်းမံမည်ဖြစ်၏။ \n\n ကိရိယာအား အားသွင်းနေစဉ် ဘက်ထရီအားထိန်းအား အလိုအလျောက် ပိတ်ထားသည်။"</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"အရေးပါမှု"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ပိတ်ဆို့ထား- ဤသတိပေးချက်များကို ဘယ်တော့မှ မပြပါနှင့်"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"နိမ့်- တိတ်ဆိတ်စွာ သတိပေးချက်များ၏ စာရင်း အောက်ပိုင်းမှာ ပြပါ"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"\'ပုံမှန်- ဤသတိပေးချက်များကို တိတ်ဆိတ်စွာ ပြပါ"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"မြင့်မား- သတိပေးချက်များ၏ စာရင်းထိပ်မှာ ပြလျက် အသံမြည်ပေးပါ"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"အရေးကြီး- : မျက်နှာပြင်မှာ ပြပေးလျက် အသံမြည်ပေးပါ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d မိနစ်တွင် (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>အထိ)</item>
<item quantity="one">တစ်မိနစ်တွင် (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> အထိ)</item>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0e0f400..cd65d85 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nå"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
<string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personlig"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibreringen"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lar appen kontrollere vibreringsfunksjonen."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lar appen kontrollere lommelykten."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lar appen ringe telefonnumre uten at du gjør noe. Dette kan resultere i uventede oppringninger og kostnader. Appen kan imidlertid ikke ringe nødnumre. Merk at skadelige apper kan påføre deg kostnader ved å ringe uten bekreftelse fra deg."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"få tilgang til nettprattjenesten for ringing"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
<string name="copy" msgid="2681946229533511987">"Kopier"</string>
<string name="paste" msgid="5629880836805036433">"Lim inn"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Lim inn som ren tekst"</string>
<string name="replace" msgid="5781686059063148930">"Erstatt"</string>
<string name="delete" msgid="6098684844021697789">"Slett"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopier URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Marker tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Angre"</string>
+ <string name="redo" msgid="7759464876566803888">"Utfør likevel"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Merket tekst"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Legg til i ordlisten"</string>
<string name="deleteText" msgid="6979668428458199034">"Slett"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Velg bakgrunnsbilde"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Varsellytteren"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Betingelsesleverandør"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Varselassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN er aktivert"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN er aktivert av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Trykk for å administrere nettverket."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Oppdatert av administratoren"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Slettet av administratoren"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"For å forlenge batterilevetiden reduserer batterispareren ytelsen til enheten din og begrenser vibrering, posisjonstjenester og mesteparten av bakgrunnsdataene. E-post, sending av meldinger og andre apper som er avhengig av synkronisering, oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokkert: Aldri vis disse varslene"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Lavt: Vis nederst i varsellisten uten lyd"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normalt: Vis disse varslene uten lyd"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Høyt: Vis øverst i varsellisten med lyd"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Haster: Vises fort på skjermen med lyd"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">I %1$d minutter (til <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">I 1 minutt (til <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Du angir viktigheten for disse varslene."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
</resources>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index ec13ebb..301094b 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"अब बन्द गर्नुहोस्"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"९९९+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
<string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
<string name="user_owner_label" msgid="2804351898001038951">"व्यक्तिगत"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"कम्पन नियन्त्रण गर्नुहोस्"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"फ्ल्यासलाईट नियन्त्रण गर्नुहोस्"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्ल्यास प्रकाशलाई नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"फोन नम्बरहरूमा सिधै कल गर्नुहोस्"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कल सेवा पहुँच गर्नुहोस्"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"काट्नुहोस्"</string>
<string name="copy" msgid="2681946229533511987">"प्रतिलिपि बनाउनुहोस्"</string>
<string name="paste" msgid="5629880836805036433">"टाँस्नुहोस्"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"सामान्य पाठको रूपमा टाँस्नुहोस्"</string>
<string name="replace" msgid="5781686059063148930">"विस्थापन गर्नुहोस्…"</string>
<string name="delete" msgid="6098684844021697789">"मेट्नुहोस्"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL को प्रतिलिप गर्नुहोस्"</string>
<string name="selectTextMode" msgid="1018691815143165326">"पाठ चयन गर्नुहोस्"</string>
+ <string name="undo" msgid="7905788502491742328">"अनडू गर्नुहोस्"</string>
+ <string name="redo" msgid="7759464876566803888">"रिडू गर्नुहोस्"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"पाठ चयनता"</string>
<string name="addToDictionary" msgid="4352161534510057874">"शब्दकोशमा थप्नुहोस्"</string>
<string name="deleteText" msgid="6979668428458199034">"मेट्नुहोस्"</string>
@@ -1113,6 +1115,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"वालपेपर परिवर्तन गर्नुहोस्"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना सुन्नेवाला"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"सर्त प्रदायक"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"सूचना सहायक"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय भयो"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g>द्वारा सक्रिय गरिएको हो"</string>
<string name="vpn_text" msgid="3011306607126450322">"नेटवर्क प्रबन्ध गर्न छुनुहोस्।"</string>
@@ -1446,12 +1449,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"तपाईँको प्रशासकद्वारा अद्यावधिक गरिएको"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"तपाईँको प्रशासकद्वारा हटाइएको"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ब्याट्रीको आयु सुधार्न, ब्याट्री संरक्षकले तपाईँको यन्त्रको कार्यसम्पादन घटाउँछ र भाइब्रेसन, स्थान सेवा र बहुसंख्यक पृष्ठभूमि डेटा सीमित गर्दछ। इमेल, सन्देश, र अन्य अनुप्रयोगहरू जुन सिङ्कमा भर पर्छन् अद्यावधिक नहुन सक्छन् जबसम्म तपाईँ तिनीहरूलाई खोल्नुहुन्न\n\n ब्याट्री संरक्षक स्वत: निस्कृय हुन्छ जब तपाईँको यन्त्र चार्ज हुँदै हुन्छ।"</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"महत्त्व"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"रोकिएका: यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"न्यून: चुपचाप सूचना सूचीको फेदमा देखाउनुहोस्"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"सामान्य: चुपचाप यी सूचनाहरू देखाउनुहोस्"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"उच्च: सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"जरुरी: स्क्रिनमा झलक्क हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other"> %1$d मिनेटको लागि (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> सम्म)</item>
<item quantity="one">एक मिनेटको लागि (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> सम्म)</item>
@@ -1517,6 +1514,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> चयन गरियो</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"विविध"</string>
- <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरू महत्त्व सेट गर्नुहुन्छ।"</string>
+ <string name="importance_from_topic" msgid="3572280439880023233">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहुन्छ।"</string>
<string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d30d836..1407991 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Persoonlijk"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder je bevestiging."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"trilling beheren"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Hiermee kan de app de trilstand beheren."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Hiermee kan de app de zaklamp bedienen."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Hiermee kan de app zonder je tussenkomst telefoonnummers bellen. Dit kan tot onverwachte kosten of oproepen leiden. De app kan hiermee geen noodnummers bellen. Schadelijke apps kunnen u geld kosten door nummers te bellen zonder om je bevestiging te vragen."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot IMS-service voor bellen"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Knippen"</string>
<string name="copy" msgid="2681946229533511987">"Kopiëren"</string>
<string name="paste" msgid="5629880836805036433">"Plakken"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Plakken als platte tekst"</string>
<string name="replace" msgid="5781686059063148930">"Vervangen..."</string>
<string name="delete" msgid="6098684844021697789">"Verwijderen"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL kopiëren"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Tekst selecteren"</string>
+ <string name="undo" msgid="7905788502491742328">"Ongedaan maken"</string>
+ <string name="redo" msgid="7759464876566803888">"Opnieuw"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Tekstselectie"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Toevoegen aan woordenboek"</string>
<string name="deleteText" msgid="6979668428458199034">"Verwijderen"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Achtergrond wijzigen"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Listener voor meldingen"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provider van voorwaarden"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Meldingsassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN is geactiveerd"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN wordt geactiveerd door <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Raak aan om het netwerk te beheren."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Geüpdatet door je beheerder"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Verwijderd door je beheerder"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Accubesparing beperkt de prestaties van je apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de accu te verlengen.\n\nAccubesparing wordt automatisch uitgeschakeld terwijl je apparaat wordt opgeladen."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Belang"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Geblokkeerd: deze meldingen nooit weergeven"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Laag: zonder geluid onder aan de lijst met meldingen weergeven"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normaal: deze meldingen zonder geluid weergeven"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Hoog: boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgent: op het scherm weergeven en geluid laten horen"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d minuten (tot <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Eén minuut (tot <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 5a3b11a..39f20f5 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ਹੁਣ ਲੌਕ ਕਰੋ"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"ਸਮੱਗਰੀਆਂ ਲੁਕਾਈਆਂ ਗਈਆਂ"</string>
<string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ਨਿੱਜੀ"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ਐਪ ਨੂੰ ਕੈਮਰੇ ਨਾਲ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ਐਪ ਨੂੰ ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਜਾਂ ਕਾਲਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਧਿਆਨ ਦਿਓ ਕਿ ਇਹ ਐਪ ਨੂੰ ਐਮਰਜੈਂਸੀ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ਕੱਟੋ"</string>
<string name="copy" msgid="2681946229533511987">"ਕਾਪੀ ਕਰੋ"</string>
<string name="paste" msgid="5629880836805036433">"ਪੇਸਟ ਕਰੋ"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"ਸਧਾਰਨ ਲਿਖਤ ਦੇ ਤੌਰ \'ਤੇ ਪੇਸਟ ਕਰੋ"</string>
<string name="replace" msgid="5781686059063148930">"ਬਦਲੋ…"</string>
<string name="delete" msgid="6098684844021697789">"ਮਿਟਾਓ"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL ਕਾਪੀ ਕਰੋ"</string>
<string name="selectTextMode" msgid="1018691815143165326">"ਟੈਕਸਟ ਚੁਣੋ"</string>
+ <string name="undo" msgid="7905788502491742328">"ਪਹਿਲਾਂ ਵਰਗਾ ਕਰੋ"</string>
+ <string name="redo" msgid="7759464876566803888">"ਮੁੜ-ਓਹੀ ਕਰੋ"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"ਟੈਕਸਟ ਚੋਣ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ਸ਼ਬਦਕੋਸ਼ ਵਿੱਚ ਜੋੜੋ"</string>
<string name="deleteText" msgid="6979668428458199034">"ਮਿਟਾਓ"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"ਵਾਲਪੇਪਰ ਬਦਲੋ"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ਸੂਚਨਾ ਸੁਣਨ ਵਾਲਾ"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ਸਥਿਤੀ ਪ੍ਰਦਾਤਾ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"ਸੂਚਨਾ ਸਹਾਇਕ"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ਸਕਿਰਿਆ ਕੀਤਾ"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> ਰਾਹੀਂ ਸਕਿਰਿਆ ਬਣਾਇਆ ਗਿਆ ਹੈ"</string>
<string name="vpn_text" msgid="3011306607126450322">"ਨੈਟਵਰਕ ਵਿਵਸਥਿਤ ਕਰਨ ਲਈ ਛੋਹਵੋ।"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"ਤੁਹਾਡੇ ਪ੍ਰਬੰਧਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"ਬੈਟਰੀ ਸਮਰੱਥਾ ਨੂੰ ਬਿਹਤਰ ਸਹਾਇਤਾ ਕਰਨ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਦਾ ਪ੍ਰਦਰਸ਼ਨ ਘਟਾਉਂਦਾ ਹੈ ਅਤੇ ਵਾਈਬ੍ਰੇਸ਼ਨ, ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਅਤੇ ਜ਼ਿਆਦਾਤਰ ਪਿਛੋਕੜ ਡਾਟਾ ਨੂੰ ਸੀਮਿਤ ਕਰਦਾ ਹੈ। ਈਮੇਲ, ਮੈਸੇਜਿੰਗ ਅਤੇ ਹੋਰ ਐਪਸ, ਜੋ ਸਿੰਕਿੰਗ ਤੇ ਨਿਰਭਰ ਹਨ, ਉਹ ਉਦੋਂ ਤੱਕ ਅਪਡੇਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਖੋਲ੍ਹਦੇ ਨਹੀਂ।\n\nਬੈਟਰੀ ਸੇਵਰ ਆਟੋਮੈਟਿਕਲੀ ਬੰਦ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਚਾਰਜ ਹੋ ਰਹੀ ਹੁੰਦੀ ਹੈ।"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"ਬਲੌਕ ਕੀਤਾ: ਇਹ ਸੂਚਨਾਵਾਂ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"ਘੱਟ: ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ਸਧਾਰਨ: ਇਹ ਸੂਚਨਾਵਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"ਵੱਧ: ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ਜ਼ਰੂਰੀ: ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d ਮਿੰਟਾਂ ਤੱਕ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ਤੱਕ) </item>
<item quantity="other">%1$d ਮਿੰਟਾਂ ਤੱਕ (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> ਤੱਕ)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ਚੁਣਿਆ ਗਿਆ</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"ਵਿਵਿਧ"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f206d82..f3e50b5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Zablokuj teraz"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
<string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
<string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobiste"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"sterowanie wibracjami"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Pozwala aplikacji na sterowanie wibracjami."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Pozwala aplikacji na sterowanie latarką."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Pozwala aplikacji na dzwonienie pod numery telefonów bez Twojej wiedzy. Może to skutkować nieoczekiwanymi opłatami lub połączeniami. Aplikacja nie może dzwonić pod numery alarmowe. Złośliwe aplikacje mogą generować koszty, wykonując połączenia bez Twojego potwierdzenia."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"usługa telefoniczna z dostępem do komunikatora"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Wytnij"</string>
<string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
<string name="paste" msgid="5629880836805036433">"Wklej"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Wklej jako zwykły tekst"</string>
<string name="replace" msgid="5781686059063148930">"Zastąp"</string>
<string name="delete" msgid="6098684844021697789">"Usuń"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiuj adres URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Zaznacz tekst"</string>
+ <string name="undo" msgid="7905788502491742328">"Cofnij"</string>
+ <string name="redo" msgid="7759464876566803888">"Ponów"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Zaznaczanie tekstu"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Dodaj do słownika"</string>
<string name="deleteText" msgid="6979668428458199034">"Usuń"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmień tapetę"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Odbiornik powiadomień"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Dostawca warunków"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asystent powiadomień"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktywny"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Obsługa sieci VPN została włączona przez aplikację <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotknij, aby zarządzać siecią."</string>
@@ -1458,13 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Zaktualizowane przez administratora"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Usunięty przez administratora"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Zablokowana: nigdy nie pokazuj tych powiadomień"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Niska: pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normalna: pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Wysoka: pokazuj na początku listy powiadomień i odtwarzaj dźwięk"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Pilna: wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="few">Przez %1$d minuty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="many">Przez %1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1548,8 +1544,6 @@
<item quantity="one">Wybrano <xliff:g id="COUNT_0">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Inne"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ustawiłeś ważność tych powiadomień."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 7e33baa..89bbbe8 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Recortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
<string name="replace" msgid="5781686059063148930">"Substituir..."</string>
<string name="delete" msgid="6098684844021697789">"Excluir"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
+ <string name="redo" msgid="7759464876566803888">"Refazer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Seleção de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
<string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificações e emitir som"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar parcialmente na tela e emitir som"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f2e9402..f559dbb 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite à aplicação controlar a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"aceder ao serviço de chamadas IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
<string name="replace" msgid="5781686059063148930">"Substituir..."</string>
<string name="delete" msgid="6098684844021697789">"Eliminar"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Anular"</string>
+ <string name="redo" msgid="7759464876566803888">"Refazer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selecção de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
<string name="deleteText" msgid="6979668428458199034">"Eliminar"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar imagem de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviço de escuta de notificações"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Fornecedor de condição"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificações"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN foi ativada pelo <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerir a rede."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado pelo administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Importância"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueado: nunca mostrar estas notificações"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baixo: mostrar na parte inferior da lista de notificações sem som"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar estas notificações sem som"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Elevado: mostrar na parte superior da lista de notificações com som"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar no ecrã com som"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Durante %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Durante um minuto (até às <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1479,7 +1476,7 @@
<item quantity="one">Durante 1 h</item>
</plurals>
<string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
- <string name="zen_mode_alarm" msgid="9128205721301330797">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
+ <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
<string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
<string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</string>
<string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 7e33baa..89bbbe8 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Bloquear agora"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Recortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Colar como texto simples"</string>
<string name="replace" msgid="5781686059063148930">"Substituir..."</string>
<string name="delete" msgid="6098684844021697789">"Excluir"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiar URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selecionar texto"</string>
+ <string name="undo" msgid="7905788502491742328">"Desfazer"</string>
+ <string name="redo" msgid="7759464876566803888">"Refazer"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Seleção de texto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Adicionar ao dicionário"</string>
<string name="deleteText" msgid="6979668428458199034">"Excluir"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Alterar plano de fundo"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Ouvinte de notificações"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Provedor de condições"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Assistente de notificação"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ativada"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"A VPN está ativada por <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Toque para gerenciar a rede."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Atualizado pelo administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Excluído pelo seu administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloqueada: nunca mostrar essas notificações"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Baixa: mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: mostrar essas notificações de forma silenciosa"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Alta: mostrar na parte superior da lista de notificações e emitir som"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: mostrar parcialmente na tela e emitir som"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Por %1$d minutos (até às <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> selecionados</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diversos"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Você definiu a importância dessas notificações."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c716c74..4086e69 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -224,6 +224,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Blocați acum"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"˃999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
<string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -354,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
@@ -863,10 +862,13 @@
<string name="cut" msgid="3092569408438626261">"Decupaţi"</string>
<string name="copy" msgid="2681946229533511987">"Copiați"</string>
<string name="paste" msgid="5629880836805036433">"Inserați"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Inserați ca text simplu"</string>
<string name="replace" msgid="5781686059063148930">"Înlocuiţi..."</string>
<string name="delete" msgid="6098684844021697789">"Ștergeți"</string>
<string name="copyUrl" msgid="2538211579596067402">"Copiați adresa URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Selectați text"</string>
+ <string name="undo" msgid="7905788502491742328">"Anulați"</string>
+ <string name="redo" msgid="7759464876566803888">"Repetați"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Selectare text"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Adăugați în dicţionar"</string>
<string name="deleteText" msgid="6979668428458199034">"Ștergeți"</string>
@@ -1114,6 +1116,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Modificaţi imaginea de fundal"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Serviciu de citire a notificărilor"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Furnizor de condiții"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent pentru notificări"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN activat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN este activată de <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Atingeți pentru a gestiona reţeaua."</string>
@@ -1449,13 +1452,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizat de un administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Șters de administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blocate: aceste notificări nu se afișează niciodată"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Redusă: se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normală: aceste notificări se afișează fără a se emite un sunet"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Ridicată: se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgente: se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="few">Timp de %1$d minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Timp de %1$d de minute (până la <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1530,8 +1526,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> selectat</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Diverse"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Dvs. setați importanța acestor notificări."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 5a2dcd9..ee39b83 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Заблокировать"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">">999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
<string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Личные данные"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Управление функцией вибросигнала"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Приложение сможет контролировать вибросигналы."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"Управление вспышкой"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Приложение сможет контролировать вспышку."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Осуществление телефонных вызовов"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Приложение сможет без вашего участия звонить на любой номер телефона. Это не относится к номерам экстренных служб. Вредоносные программы смогут совершать вызовы без вашего разрешения, что может привести к непредвиденным расходам."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"совершение звонков с помощью службы IMS"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Вырезать"</string>
<string name="copy" msgid="2681946229533511987">"Копировать"</string>
<string name="paste" msgid="5629880836805036433">"Вставить"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Вставить как обычный текст"</string>
<string name="replace" msgid="5781686059063148930">"Заменить"</string>
<string name="delete" msgid="6098684844021697789">"Удалить"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копировать URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Выбрать текст"</string>
+ <string name="undo" msgid="7905788502491742328">"Отменить"</string>
+ <string name="redo" msgid="7759464876566803888">"Повторить"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Выбор текста"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Добавить в словарь"</string>
<string name="deleteText" msgid="6979668428458199034">"Удалить"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба просмотра уведомлений"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Поставщик условий"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Ассистент уведомлений"</string>
<string name="vpn_title" msgid="19615213552042827">"Сеть VPN активна"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Сеть VPN активирована приложением <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Нажмите, чтобы открыть настройки."</string>
@@ -1458,13 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Обновлено администратором"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Удалено администратором"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблокировано: не показывать эти уведомления"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Низкая: показывать без звука в конце списка уведомлений"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Обычная: показывать уведомления без звука"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Высокая: показывать со звуком в начале списка уведомлений"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Срочно: показывать со звуковым сигналом поверх всех окон"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d минуты (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1548,8 +1544,6 @@
<item quantity="other">Выбрано: <xliff:g id="COUNT_1">%1$d</xliff:g></item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Другое"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Вы определяете важность этих уведомлений."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
</resources>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 8584f0d..5364c98 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"දැන් අගුළු දමන්න"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
<string name="safeMode" msgid="2788228061547930246">"ආරක්ෂිත ආකාරය"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
<string name="user_owner_label" msgid="2804351898001038951">"පෞද්ගලික"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"කම්පනය පාලනය කිරීම"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"සැණෙළි ආලෝකය පාලනය කරන්න"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"සැණෙළිය පාලනයට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"දුරකථන අංක වෙත ඍජුවම අමතන්න"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ඔබගේ මැදිහත් වීමක් නොමැතිව දුරකථන අංක ඇමතීමට යෙදුමට අවසර දෙන්න. මෙහි ප්රතිඑලය වන්නේ අනපේක්ෂිත අයකිරීම් හෝ ඇමතුම් ඇතිවීමයි. මෙයන් හදිසි අංක වලට ඇමතුම් ගැනීමට යෙදුමට අවසර නොදෙන බවට සටහන් කරගන්න. ඔබගේ අනුදැනුමක් නොමැතිව ඇමතුම් ගැනීමෙන් අනිෂ්ට යෙදුම් ඔබගේ මුදල් නිකරුණේ වැය කරයි."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string>
@@ -860,10 +859,13 @@
<string name="cut" msgid="3092569408438626261">"කපන්න"</string>
<string name="copy" msgid="2681946229533511987">"පිටපත් කරන්න"</string>
<string name="paste" msgid="5629880836805036433">"අලවන්න"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"සරල පෙළ ලෙස අලවන්න"</string>
<string name="replace" msgid="5781686059063148930">"ප්රතිස්ථාපනය කරන්න..."</string>
<string name="delete" msgid="6098684844021697789">"මකන්න"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL පිටපත් කරන්න"</string>
<string name="selectTextMode" msgid="1018691815143165326">"පෙළ තෝරන්න"</string>
+ <string name="undo" msgid="7905788502491742328">"අස් කරන්න"</string>
+ <string name="redo" msgid="7759464876566803888">"යළි කරන්න"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"පෙළ තේරීම"</string>
<string name="addToDictionary" msgid="4352161534510057874">"ශබ්ද කෝෂයට එකතු කරන්න"</string>
<string name="deleteText" msgid="6979668428458199034">"මකන්න"</string>
@@ -1109,6 +1111,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"බිතුපත වෙනස් කරන්න"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"දැනුම්දීම් අසන්නා"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"තත්ත්වය සපයන්නා"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"දැනුම්දීම් සහායක"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN ක්රියාත්මකයි"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> මඟින් VPN සක්රීය කරන ලදි"</string>
<string name="vpn_text" msgid="3011306607126450322">"ජාලය කළමනාකරණය කිරීමට ස්පර්ශ කරන්න."</string>
@@ -1442,13 +1445,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"ඔබගේ පරිපාලක විසින් යාවත්කාලීන කරන ලදී"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"ඔබගේ පරිපාලක විසින් මකන ලද"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊමේල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්රියව අක්රිය වේ."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"අවහිර කළ: මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"අඩු: දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"සාමාන්ය: නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"වැඩි: දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"හදිසි: තිරයට පැමිණ ශබ්ද කරන්න"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">මිනිත්තු %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
<item quantity="other">මිනිත්තු %1$d ක් සඳහා (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> තෙක්)</item>
@@ -1514,8 +1510,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ක් තෝරන ලදි</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"විවිධාකාර"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d26dcc6..90ccd54 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Uzamknúť"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
<string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osobné"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"prístup k službe volania IMS"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Vystrihnúť"</string>
<string name="copy" msgid="2681946229533511987">"Kopírovať"</string>
<string name="paste" msgid="5629880836805036433">"Prilepiť"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Prilepiť ako obyčajný text"</string>
<string name="replace" msgid="5781686059063148930">"Nahradiť•"</string>
<string name="delete" msgid="6098684844021697789">"Odstrániť"</string>
<string name="copyUrl" msgid="2538211579596067402">"Skopírovať webovú adresu"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Vybrať text"</string>
+ <string name="undo" msgid="7905788502491742328">"Späť"</string>
+ <string name="redo" msgid="7759464876566803888">"Znova"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Výber textu"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Pridať do slovníka"</string>
<string name="deleteText" msgid="6979668428458199034">"Odstrániť"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Zmeniť tapetu"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Aplikácia na počúvanie upozornení"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Poskytovateľ podmienky"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistent upozornení"</string>
<string name="vpn_title" msgid="19615213552042827">"Sieť VPN je aktivovaná"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Aplikáciu <xliff:g id="APP">%s</xliff:g> aktivovala sieť VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotykom môžete spravovať sieť."</string>
@@ -1458,12 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Aktualizované správcom"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Odstránený správcom"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"S cieľom predĺžiť výdrž batérie zníži šetrič batérie výkonnosť zariadenia a obmedzí vibrácie, služby určovania polohy a dátové prenosy na pozadí. Pošta, čet a ďalšie aplikácie, ktoré sa spoliehajú na synchronizáciu, sa možno nebudú aktualizovať, dokiaľ ich neotvoríte.\n\nPri nabíjaní zariadenia sa šetrič batérie automaticky vypne."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Dôležitosť"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokované: Tieto upozornenia nikdy nezobrazovať"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Nízke: Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normálne: Tieto upozornenia zobrazovať bez zvukového signálu"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Vysoké: Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Neodkladné: Zobraziť cez obrazovku so zvukovým signálom"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="few">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="many">%1$d minúty (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 6746a9e..4e9b1c5 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Zakleni zdaj"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
<string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Osebno"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"nadzor vibriranja"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogoča nadzor vibriranja."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogoča nadzor svetilke."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogoča klicanje telefonskih številk brez vašega posredovanja. Zaradi tega lahko pride do nepričakovanih stroškov ali klicev. Aplikaciji to ne dovoljuje opravljanja klicev v sili. Zlonamerne aplikacije lahko kličejo brez vaše potrditve, kar vas lahko drago stane."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"dostop do storitve za klicanje IMS"</string>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Izreži"</string>
<string name="copy" msgid="2681946229533511987">"Kopiraj"</string>
<string name="paste" msgid="5629880836805036433">"Prilepi"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Prilepi kot navadno besedilo"</string>
<string name="replace" msgid="5781686059063148930">"Zamenjaj •"</string>
<string name="delete" msgid="6098684844021697789">"Izbriši"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiraj URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Izbira besedila"</string>
+ <string name="undo" msgid="7905788502491742328">"Razveljavi"</string>
+ <string name="redo" msgid="7759464876566803888">"Uveljavi"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Izbrano besedilo"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Dodaj v slovar"</string>
<string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Spreminjanje ozadja"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Poslušalec obvestil"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ponudnik pogojev"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Pomočnik za obvestila"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN je aktivirala aplikacija <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Dotaknite se, če želite upravljati omrežje."</string>
@@ -1458,13 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Posodobil skrbnik"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisal skrbnik"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blokirano: nikoli ne prikaži teh obvestil"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Manj pomembno: prikaži na dnu seznama obvestil brez zvoka"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Običajno: prikaži ta obvestila brez zvoka"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Pomembno: prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Nujno: za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%d minuto (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="two">%d minuti (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1548,8 +1544,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> izbranih</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Razno"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Vi določite raven pomembnosti teh obvestil."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 4b1a45c..be9c709 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Kyç tani"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Përmbajtjet janë të fshehura"</string>
<string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
<string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Lejon aplikacion të krijojë fotografi dhe video me kamerën. Kjo leje mundëson përdorimin e kamerës në çdo kohë pa konfirmimin tënd."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrollo dridhjen"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Lejon aplikacionin të kontrollojë dridhësin."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollo elektrikun"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Lejon aplikacionin të kontrollojë elektrikun."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefono drejtpërdrejt numrat e telefonit"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Lejon aplikacionin të telefonojë numra pa ndërhyrjen tënde. Kjo mund të rezultojë në tarifa ose telefonata të papritura. Ki parasysh se kjo nuk e lejon aplikacionin të telefonojë numra urgjence. Aplikacione keqdashëse mund të të kushtojnë para duke kryer telefonata pa konfirmimin tënd."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"qasje në shërbimin e telefonatave IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Pri"</string>
<string name="copy" msgid="2681946229533511987">"Kopjo"</string>
<string name="paste" msgid="5629880836805036433">"Ngjit"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Ngjite si tekst të thjeshtë"</string>
<string name="replace" msgid="5781686059063148930">"Zëvendëso…"</string>
<string name="delete" msgid="6098684844021697789">"Fshi"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopjo URL-në"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Përzgjidh tekstin"</string>
+ <string name="undo" msgid="7905788502491742328">"Zhbëj"</string>
+ <string name="redo" msgid="7759464876566803888">"Ribëj"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Përzgjedhja e tekstit"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Shto në fjalor"</string>
<string name="deleteText" msgid="6979668428458199034">"Fshi"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ndrysho imazhin e sfondit"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Dëgjues njoftimesh"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Ofrues kushtesh"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Asistenti i njoftimeve"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN-ja u aktivizua"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN-ja është aktivizuar nga <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Prek për të menaxhuar rrjetin."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Përditësuar nga administratori"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"U fshi nga administratori yt"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Për të përmirësuar jetëgjatësinë e baterisë, opsioni i kursimit të baterisë ul rendimentin e pajisjes tënde si dhe kufizon dridhjet dhe shumicën e të dhënave në sfond. Mail-i, mesazhet dhe aplikacionet e tjera që sinkronizohen automatikisht mund të mos përditësohen pa i hapur.\n\nKursimi i baterisë çaktivizohet automatikisht kur pajisja vihet në ngarkim."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Të bllokuara: Mos i shfaq asnjëherë këto njoftime"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Të ulëta: Shfaqi në heshtje në fund të listës së njoftimeve"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normale: Shfaqi këto njoftime në heshtje"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Të larta: Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Urgjente: Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Për %1$d minuta (deri në <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Për një minutë (deri në <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> i zgjedhur</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Të ndryshme"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d7801b1..a3618ab 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -224,6 +224,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Закључај одмах"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
<string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Лично"</string>
@@ -354,8 +355,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контрола вибрације"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозвољава апликацији да контролише вибрацију."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозвољава апликацији да контролише блиц."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Дозвољава апликацији да позива бројеве телефона без ваше дозволе. Ово може да доведе до неочекиваних трошкова или позива. Имајте на уму да ово не дозвољава апликацији да позива бројеве за хитне случајеве. Злонамерне апликације могу да позивају без ваше потврде, што може да доведе до трошкова."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"приступ услузи позива помоћу размене тренутних порука"</string>
@@ -863,10 +862,13 @@
<string name="cut" msgid="3092569408438626261">"Исеци"</string>
<string name="copy" msgid="2681946229533511987">"Копирај"</string>
<string name="paste" msgid="5629880836805036433">"Налепи"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Налепи као обичан текст"</string>
<string name="replace" msgid="5781686059063148930">"Замени..."</string>
<string name="delete" msgid="6098684844021697789">"Избриши"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копирај URL адресу"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Изабери текст"</string>
+ <string name="undo" msgid="7905788502491742328">"Опозови"</string>
+ <string name="redo" msgid="7759464876566803888">"Понови"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Избор текста"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Додај у речник"</string>
<string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
@@ -1114,6 +1116,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Промена позадине"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Монитор обавештења"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Добављач услова"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Помоћник за обавештења"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN је активиран"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Апликација <xliff:g id="APP">%s</xliff:g> је активирала VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"Додирните да бисте управљали мрежом."</string>
@@ -1449,13 +1452,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ажурирао је администратор"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Избрисао је ваш адмиистратор"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију можда неће да се ажурирају ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Блокирана: Ова обавештења се никада не приказују"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Ниска: Приказују се у дну листе обавештења без звука"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Уобичајена: Ова обавештења се приказују без звука"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Висока: Приказују се у врху листе обавештења и активира се звучни сигнал"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Хитна: Накратко се приказују на екрану и активира се звучни сигнал"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d минут (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d минута (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1530,8 +1526,6 @@
<item quantity="other">Изабрано је <xliff:g id="COUNT_1">%1$d</xliff:g> ставки</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Разно"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ви подешавате важност ових обавештења."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8986073..b07dc28 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Lås nu"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
<string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personligt"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"styra vibration"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Tillåter att appen styr vibrationen."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillåter att appen styr lampan."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Tillåter att appen ringer telefonnummer utan någon aktiv åtgärd från dig. Detta kan leda till oväntade avgifter och samtal. Observera att appen inte tillåts ringa nödsamtal. Skadliga appar kan ringa utan ditt godkännande och detta kan kosta pengar."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"tillgång till tjänsten för snabbmeddelanden vid samtal"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
<string name="copy" msgid="2681946229533511987">"Kopiera"</string>
<string name="paste" msgid="5629880836805036433">"Klistra in"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Klistra in som oformaterad text"</string>
<string name="replace" msgid="5781686059063148930">"Ersätt..."</string>
<string name="delete" msgid="6098684844021697789">"Ta bort"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiera webbadress"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Markera text"</string>
+ <string name="undo" msgid="7905788502491742328">"Ångra"</string>
+ <string name="redo" msgid="7759464876566803888">"Gör om"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Textmarkering"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Lägg till i ordlista"</string>
<string name="deleteText" msgid="6979668428458199034">"Ta bort"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Ändra bakgrund"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Meddelandelyssnare"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Leverantör"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Aviseringsassistent"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN är aktiverat"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN aktiveras av <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tryck om du vill hantera nätverket."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Uppdaterat av administratören"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Paketet har raderats av administratören"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Relevans"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Blockerad: Visa aldrig dessa aviseringar"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Låg: Visa längst ned i aviseringslistan – utan ljud"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Visa aviseringarna – utan ljud"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Hög: Visa högst upp i aviseringslistan – med ljud"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Brådskande: Visa på skärmen – med ljud"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">I %1$d minuter (till kl. <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">I en minut (till kl. <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f00ff44..cf0063c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Funga sasa"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
<string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
<string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Binafsi"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"piga simu moja kwa moja kwa nambari za simu"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Inaruhusu programu kupiga nambari za simu bila ya wewe kuingilia kati. Hii inaweza kusababisha gharama zisizotarajiwa au simu. Kumbuka kuwa hii hairuhusu programu kupiga nambari za dharura. Programu hasidi zinaweza kukugharimu pesa kwa kupiga simu bila uthibitisho wako."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"fikia huduma ya simu ya IMS"</string>
@@ -794,7 +793,7 @@
<string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
<string name="save_password_never" msgid="8274330296785855105">"Katu"</string>
<string name="open_permission_deny" msgid="7374036708316629800">"Hauna idhini ya kufungua ukurasa huu."</string>
- <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao klipu."</string>
+ <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao wa kunakili."</string>
<string name="more_item_label" msgid="4650918923083320495">"Zaidi"</string>
<string name="prepend_shortcut_label" msgid="2572214461676015642">"Menyu+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"mwanya"</string>
@@ -860,10 +859,13 @@
<string name="cut" msgid="3092569408438626261">"Kata"</string>
<string name="copy" msgid="2681946229533511987">"Nakala"</string>
<string name="paste" msgid="5629880836805036433">"Bandika"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Bandika kama maandishi dhahiri"</string>
<string name="replace" msgid="5781686059063148930">"Badilisha..."</string>
<string name="delete" msgid="6098684844021697789">"Futa"</string>
<string name="copyUrl" msgid="2538211579596067402">"Nakili URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Chagua maandishi"</string>
+ <string name="undo" msgid="7905788502491742328">"Tendua"</string>
+ <string name="redo" msgid="7759464876566803888">"Rejesha"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Uchaguzi wa maandishi?"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Ongeza kwenye kamusi"</string>
<string name="deleteText" msgid="6979668428458199034">"Futa"</string>
@@ -1109,6 +1111,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Badilisha mandhari"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Kisikilizi cha arifa"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Mtoa masharti"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Mratibu wa arifa"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN imewezeshwa"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN imeamilishwa na <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Gusa ili kudhibiti mtandao."</string>
@@ -1442,13 +1445,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Kimesasiswa na msimamizi wako"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Kilifutwa na msimamizi wako"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Kusaidia kuboresha muda wa matumizi ya betri, inayookoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali, na data nyingi ya chini chini. Barua pepe, ujumbe na programu nyingine zinazotege,ea usawazishaji huenda zisisasishwe usipozifungua.\n\nInayookoa betri hujizima kiotomatiki kifaa chako kinapokuwa kinachaji."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Imezuiwa: Usionyeshe arifa hizi kamwe"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Chini: Onyesha katika sehemu ya chini ya orodha ya arifa bila kutoa sauti"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Kawaida: Onyesha arifa hizi bila sauti"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Juu: Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Muhimu: Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Kwa dakika %1$d (hadi <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Kwa dakika moja (hadi <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1514,8 +1510,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> kimechaguliwa</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Anuwai"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Uliweka umuhimu wa arifa hizi."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
</resources>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 5a007ce..7f57ded 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -40,5 +40,6 @@
<!-- Use a larger scaling span for larger screen devices. -->
<dimen name="config_minScalingSpan">32mm</dimen>
+ <integer name="config_dockedStackDividerSnapMode">1</integer>
</resources>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index e419eea..ecefb77 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"இப்போது பூட்டு"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
<string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
<string name="user_owner_label" msgid="2804351898001038951">"தனிப்பட்ட"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ஃப்லாஷ்லைட்டை இயக்குதல்"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ஃப்ளாஷ் லைட்டைக் கட்டுப்படுத்த, பயன்பாட்டை அனுமதிக்கிறது."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது பயன்பாட்டை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"வெட்டு"</string>
<string name="copy" msgid="2681946229533511987">"நகலெடு"</string>
<string name="paste" msgid="5629880836805036433">"ஒட்டு"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"எளிய உரையாக ஒட்டு"</string>
<string name="replace" msgid="5781686059063148930">"மாற்று..."</string>
<string name="delete" msgid="6098684844021697789">"நீக்கு"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL ஐ நகலெடு"</string>
<string name="selectTextMode" msgid="1018691815143165326">"உரையைத் தேர்வுசெய்க"</string>
+ <string name="undo" msgid="7905788502491742328">"செயல்தவிர்"</string>
+ <string name="redo" msgid="7759464876566803888">"மீண்டும்செய்"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"உரை தேர்ந்தெடுத்தல்"</string>
<string name="addToDictionary" msgid="4352161534510057874">"அகராதியில் சேர்"</string>
<string name="deleteText" msgid="6979668428458199034">"நீக்கு"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"வால்பேப்பரை மாற்று"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"அறிவிப்புகளைக் கண்காணிக்கும் சேவை"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"நிபந்தனை வழங்குநர்"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"அறிவிப்பு உதவி"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN செயல்படுத்தப்பட்டது"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ஆல் VPN செயல்படுத்தப்பட்டது"</string>
<string name="vpn_text" msgid="3011306607126450322">"நெட்வொர்க்கை நிர்வகிக்கத் தொடவும்."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"நிர்வாகி நீக்கிவிட்டார்"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"பேட்டரி ஆயுளை மேம்படுத்த, பேட்டரி சேமிப்பான் உங்கள் சாதனத்தின் செயல்திறனைக் குறைத்து, அதிர்வு, இடச் சேவைகள் மற்றும் பெரும்பாலான பின்புலத் தரவு போன்றவற்றைக் கட்டுப்படுத்துகிறது. ஒத்திசைவைச் சார்ந்துள்ள மின்னஞ்சல், செய்தியிடல் மற்றும் பிற பயன்பாடுகள் திறக்கும்வரை, அவை புதுப்பிக்கப்படாமல் இருக்கலாம்.\n\nஉங்கள் ஃபோன் சார்ஜ் செய்யப்படும்போது, பேட்டரி சேமிப்பான் தானாகவே முடங்கும்."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"முக்கியத்துவம்"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"தடுக்கப்பட்டது: இந்த அறிவிப்புகளை ஒருபோதும் காட்டாது"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"குறைவு: ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டும்"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"இயல்பு: ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டும்"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"அதிகம்: அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டும்"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"அவசரம்: ஒலியுடன் திரையில் தோன்றும்"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d நிமிடங்களுக்கு (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> வரை)</item>
<item quantity="one">ஒரு நிமிடத்திற்கு (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> வரை)</item>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index a6c80ad..b1bccd2 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ఇప్పుడు లాక్ చేయండి"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్లు దాచబడ్డాయి"</string>
<string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
<string name="user_owner_label" msgid="2804351898001038951">"వ్యక్తిగతం"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"వైబ్రేషన్ను నియంత్రించడం"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ఫ్లాష్కాంతిని నియంత్రించడం"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ఫ్లాష్లైట్ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ఫోన్ నంబర్లకు నేరుగా కాల్ చేయడం"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్లు రావచ్చు. ఇది అత్యవసర నంబర్లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతించదని గుర్తుంచుకోండి. హానికరమైన అనువర్తనాలు మీ నిర్ధారణ లేకుండానే కాల్లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"కత్తిరించు"</string>
<string name="copy" msgid="2681946229533511987">"కాపీ చేయి"</string>
<string name="paste" msgid="5629880836805036433">"అతికించు"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"సాదా వచనం వలె అతికించు"</string>
<string name="replace" msgid="5781686059063148930">"భర్తీ చేయండి..."</string>
<string name="delete" msgid="6098684844021697789">"తొలగించు"</string>
<string name="copyUrl" msgid="2538211579596067402">"URLని కాపీ చేయి"</string>
<string name="selectTextMode" msgid="1018691815143165326">"వచనాన్ని ఎంచుకోండి"</string>
+ <string name="undo" msgid="7905788502491742328">"చర్య రద్దు చేయి"</string>
+ <string name="redo" msgid="7759464876566803888">"చర్యను పునరావృతం చేయి"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"వచన ఎంపిక"</string>
<string name="addToDictionary" msgid="4352161534510057874">"నిఘంటువుకు జోడించు"</string>
<string name="deleteText" msgid="6979668428458199034">"తొలగించు"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"వాల్పేపర్ను మార్చండి"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"నోటిఫికేషన్ పరిశీలన"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"షరతు ప్రదాత"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"నోటిఫికేషన్ సహాయకం"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN సక్రియం చేయబడింది"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> ద్వారా VPN సక్రియం చేయబడింది"</string>
<string name="vpn_text" msgid="3011306607126450322">"నెట్వర్క్ను నిర్వహించడానికి తాకండి."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"మీ నిర్వాహకుడు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"మీ నిర్వాహకులు తొలగించారు"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్ను, స్థాన సేవలను మరియు ఎక్కువ నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర అనువర్తనాలు మీరు వాటిని తెరిస్తే మినహా నవీకరించబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"ప్రాముఖ్యత"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"బ్లాక్ చేయబడింది: ఈ నోటిఫికేషన్లను ఎప్పుడూ చూపదు"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"తక్కువ: నోటిఫికేషన్ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"సాధారణం: ఈ నోటిఫికేషన్లను శబ్దం లేకుండా చూపుతుంది"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"అధికం: నోటిఫికేషన్ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"అత్యవసరం: స్క్రీన్పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d నిమిషాల పాటు (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> వరకు)</item>
<item quantity="one">ఒక నిమిషం పాటు (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> వరకు)</item>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3576093..0b8e60d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ล็อกเลย"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</string>
<string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
<string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ส่วนตัว"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ควบคุมการสั่นเตือน"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"อนุญาตให้แอปพลิเคชันโทรเข้าโทรศัพท์โดยไม่ต้องให้คุณจัดการ ซึ่งอาจทำให้มีการเรียกเก็บเงินหรือการโทรที่ไม่คาดคิด โปรดทราบว่าการทำงานนี้ไม่ได้อนุญาตให้แอปพลิเคชันโทรไปหมายเลขฉุกเฉิน แอปพลิเคชันที่เป็นอันตรายอาจทำให้คุณต้องเสียค่าบริการด้วยการโทรโดยไม่ขอการยืนยันจากคุณ"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"เข้าถึงบริการโทร IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"ตัด"</string>
<string name="copy" msgid="2681946229533511987">"คัดลอก"</string>
<string name="paste" msgid="5629880836805036433">"วาง"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"วางเป็นข้อความธรรมดา"</string>
<string name="replace" msgid="5781686059063148930">"แทนที่..."</string>
<string name="delete" msgid="6098684844021697789">"ลบ"</string>
<string name="copyUrl" msgid="2538211579596067402">"คัดลอก URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"เลือกข้อความ"</string>
+ <string name="undo" msgid="7905788502491742328">"เลิกทำ"</string>
+ <string name="redo" msgid="7759464876566803888">"ทำซ้ำ"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"การเลือกข้อความ"</string>
<string name="addToDictionary" msgid="4352161534510057874">"เพิ่มในพจนานุกรม"</string>
<string name="deleteText" msgid="6979668428458199034">"ลบ"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"เปลี่ยนวอลเปเปอร์"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"ตัวฟังการแจ้งเตือน"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"ผู้เสนอเงื่อนไข"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"ผู้ช่วยการแจ้งเตือน"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN เปิดใช้งานแล้ว"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"เปิดใช้งาน VPN โดย <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"แตะเพื่อจัดการเครือข่าย"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"อัปเดตโดยผู้ดูแลระบบ"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"ลบโดยผู้ดูแลระบบของคุณ"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยปรับปรุงอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"บล็อก: อย่าแสดงการแจ้งเตือนเหล่านี้"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"ต่ำ: แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"ปกติ: แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"สูง: แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ด่วน: แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">ระยะเวลา %1$d นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">ระยะเวลา 1 นาที (จนถึงเวลา <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">เลือกไว้ <xliff:g id="COUNT_0">%1$d</xliff:g> รายการ</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"เบ็ดเตล็ด"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 639d368..02a3587 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"I-lock ngayon"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
<string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kontrolin ang pag-vibrate"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Pinapayagan ang app na kontrolin ang vibrator."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Pinapayagan ang app na kontrolin ang flashlight."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Pinapayagan ang app na tumawag sa mga numero ng telepono nang wala ng iyong panghihimasok. Maaari itong magresulta sa mga hindi inaasahang pagsingil o tawag. Tandaan na hindi nito pinapayagan ang app na tumawag sa mga numerong pang-emergency. Maaaring magpagastos sa iyo ng pera ang nakakahamak na apps sa pamamagitan ng pagtawag nang wala ng iyong kumpirmasyon."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"i-access ang serbisyo sa tawag ng IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"I-cut"</string>
<string name="copy" msgid="2681946229533511987">"Kopyahin"</string>
<string name="paste" msgid="5629880836805036433">"I-paste"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"I-paste bilang plain text"</string>
<string name="replace" msgid="5781686059063148930">"Palitan..."</string>
<string name="delete" msgid="6098684844021697789">"Tanggalin"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopyahin ang URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Pumili ng teksto"</string>
+ <string name="undo" msgid="7905788502491742328">"I-undo"</string>
+ <string name="redo" msgid="7759464876566803888">"Gawing muli"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Pagpili ng teksto"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Idagdag sa diksyunaryo"</string>
<string name="deleteText" msgid="6979668428458199034">"Tanggalin"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Baguhin ang wallpaper"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Notification listener"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Nagbibigay ng kundisyon"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Notification assistant"</string>
<string name="vpn_title" msgid="19615213552042827">"Naka-activate ang VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Isinaaktibo ang VPN ng <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Pindutin upang pamahalaan ang network."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Na-update ng iyong administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Na-delete ng iyong administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang pagganap ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Naka-block: Huwag kailanman ipakita ang mga notification na ito"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Mababa: Tahimik na ipakita sa ibaba ng listahan ng mga notification"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Tahimik na ipakita ang mga notification na ito"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Mataas: Ipakita sa taas ng listahan ng mga notification at mag-play ng tunog"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Agaran: Ipasilip sa screen at mag-play ng tunog"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Sa loob ng %1$d minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Sa loob ng %1$d na minuto (hanggang <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ang napili</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Iba Pa"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Ikaw ang magtatakda ng kahalagahan ng mga notification na ito."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index fea3e74..283bcebb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Şimdi kilitle"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
<string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Kişisel"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Kes"</string>
<string name="copy" msgid="2681946229533511987">"Kopyala"</string>
<string name="paste" msgid="5629880836805036433">"Yapıştır"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Düz metin olarak yapıştır"</string>
<string name="replace" msgid="5781686059063148930">"Değiştir..."</string>
<string name="delete" msgid="6098684844021697789">"Sil"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL\'yi kopyala"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Metin seç"</string>
+ <string name="undo" msgid="7905788502491742328">"Geri al"</string>
+ <string name="redo" msgid="7759464876566803888">"Yeniden yap"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Metin seçimi"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Sözlüğe ekle"</string>
<string name="deleteText" msgid="6979668428458199034">"Sil"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Duvar kağıdını değiştir"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirim dinleyici"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Durum sağlayıcı"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirim yardımcısı"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN etkinleştirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN, <xliff:g id="APP">%s</xliff:g> tarafından etkinleştirildi"</string>
<string name="vpn_text" msgid="3011306607126450322">"Ağı yönetmek için dokunun."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Yöneticiniz tarafından güncellendi"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Yöneticiniz tarafından silindi"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Engellendi: Bu bildirimleri hiçbir zaman gösterme"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Düşük: Bildirim listesinin altında sessizce göster"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Normal: Bu bildirimleri sessizce göster"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Yüksek: Bildirim listesinin üstünde göster ve ses çıkar"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Acil: Ekrana getir ve ses çıkar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Bir dakika için (şu saate kadar: <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> öğe seçildi</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Çeşitli"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Bu bildirimlerin önem derecesini ayarladınız."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index e38ec1d..fce4cc3 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -225,6 +225,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Блокувати зараз"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
<string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
<string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Особисті дані"</string>
@@ -355,8 +356,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"контролювати вібросигнал"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволяє програмі контролювати вібросигнал."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволяє програмі контролювати світловий сигнал."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Дозволяє програмі набирати номери телефону без вашого відома. Це може спричинити неочікуване стягнення плати чи здійснення дзвінків. Зауважте, що це не дозволяє програмі набирати екстрені номери. Шкідливі програми можуть здійснювати дзвінки без вашого підтвердження, за що з вас стягуватимуться кошти."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"отримувати доступ до телефонної служби IMS"</string>
@@ -542,8 +541,8 @@
<item msgid="9192514806975898961">"Указати"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Дом."</item>
- <item msgid="7084237356602625604">"Роб."</item>
+ <item msgid="8073994352956129127">"Домашня"</item>
+ <item msgid="7084237356602625604">"Робоча"</item>
<item msgid="1112044410659011023">"Інше"</item>
<item msgid="2374913952870110618">"Указати"</item>
</string-array>
@@ -868,10 +867,13 @@
<string name="cut" msgid="3092569408438626261">"Виріз."</string>
<string name="copy" msgid="2681946229533511987">"Копіюв."</string>
<string name="paste" msgid="5629880836805036433">"Вставити"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Вставити як простий текст"</string>
<string name="replace" msgid="5781686059063148930">"Замінити..."</string>
<string name="delete" msgid="6098684844021697789">"Видалити"</string>
<string name="copyUrl" msgid="2538211579596067402">"Копіюв. URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Вибрати текст"</string>
+ <string name="undo" msgid="7905788502491742328">"Відмінити"</string>
+ <string name="redo" msgid="7759464876566803888">"Повторити"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Вибір тексту"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Додати в словник"</string>
<string name="deleteText" msgid="6979668428458199034">"Видалити"</string>
@@ -1121,6 +1123,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Змінити фоновий малюнок"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Служба читання сповіщень"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Постачальник умов"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Диспетчер сповіщень"</string>
<string name="vpn_title" msgid="19615213552042827">"Мережу VPN активовано"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"Мережу VPN активовано програмою <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Торкніться, щоб керувати мережею."</string>
@@ -1458,12 +1461,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Оновлено адміністратором"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Видалив адміністратор"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Щоб подовжити час роботи акумулятора, функція заощадження заряду акумулятора знижує продуктивність пристрою, а також обмежує вібрацію, функції служб локації та передавання більшості фонових даних. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nФункція заощадження заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Пріоритет"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Заблоковано: не показувати ці сповіщення"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Низький пріоритет: показувати ці сповіщення внизу списку без звукового сигналу"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Стандартний пріоритет: показувати ці сповіщення без звукового сигналу"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Високий пріоритет: показувати ці сповіщення вгорі списку зі звуковим сигналом"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Терміново: показувати ці сповіщення на екрані зі звуковим сигналом"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">%1$d хвилину (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d хвилини (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index 517ac2b..519f42b 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"ابھی مقفل کریں"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
<string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android سسٹم"</string>
<string name="user_owner_label" msgid="2804351898001038951">"ذاتی"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"ارتعاش کو کنٹرول کریں"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"فلیش لائٹ کنٹرول"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"ایپ کو فلیش لائٹ کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"براہ راست فون نمبرز پر کال کریں"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"ایپ کو آپ کی مداخلت کے بغیر فون نمبروں پر کال کرنے کی اجازت دیتا ہے۔ اس کے نتیجے میں غیر متوقع چارجز یا کالیں ہوسکتی ہیں۔ نوٹ کرلیں کہ یہ ایپ کو ہنگامی نمبروں پر کال کرنے کی اجازت نہیں دیتا ہے۔ نقصان دہ ایپس آپ کی تصدیق کے بغیر کالیں کرکے آپ کی رقم صرف کروا سکتے ہیں۔"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS کال سروس تک رسائی حاصل کریں"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"کاٹیں"</string>
<string name="copy" msgid="2681946229533511987">"کاپی کریں"</string>
<string name="paste" msgid="5629880836805036433">"پیسٹ کریں"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"سادہ متن کے طور پر پیسٹ کریں"</string>
<string name="replace" msgid="5781686059063148930">"تبدیل کریں…"</string>
<string name="delete" msgid="6098684844021697789">"حذف کریں"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL کاپی کریں"</string>
<string name="selectTextMode" msgid="1018691815143165326">"متن منتخب کریں"</string>
+ <string name="undo" msgid="7905788502491742328">"کالعدم کریں"</string>
+ <string name="redo" msgid="7759464876566803888">"دوبارہ کریں"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"متن کا انتخاب"</string>
<string name="addToDictionary" msgid="4352161534510057874">"لغت میں شامل کریں"</string>
<string name="deleteText" msgid="6979668428458199034">"حذف کریں"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"وال پیپر تبدیل کریں"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"اطلاع سننے والا"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"شرط فراہم کنندہ"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"اطلاع کا معاون"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN فعال ہوگیا"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> کے ذریعہ VPN فعال ہے"</string>
<string name="vpn_text" msgid="3011306607126450322">"نیٹ ورک کا نظم کرنے کیلئے چھوئیں۔"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"آپ کے منتظم نے اپ ڈيٹ کر دیا"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"آپ کے منتظم کی جانب سے حذف کر دیا گیا"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"بیٹری کی میعاد بہتر کرنے میں مدد کرنے کیلئے، بیٹری سیور آپ کے آلہ کی کارکردگی کم کر دیتی ہے اور وائبریشن، مقام کی سروسز اور پس منظر کا بیشتر ڈیٹا محدود کر دیتی ہے۔ ای میل، پیغام رسانی اور مطابقت پذیری پر منحصر دیگر ایپس ممکن ہے اس وقت تک اپ ڈیٹ نہ ہوں جب تک آپ انہیں نہ کھولیں۔\n\nآپ کا آلہ چارج ہوتے وقت بیٹری سیور خود بخود آف ہو جاتی ہے۔"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"مسدود کردہ: یہ اطلاعات کبھی مت دکھائیں"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"پست: اطلاعات کی فہرست کے نیچے خاموشی سے دکھائیں"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"عام: خاموشی سے یہ اطلاعات دکھائیں"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"اعلی: اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"ارجنٹ: اسکرین پر دکھائیں اور آواز چلائیں"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d منٹ کیلئے (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> تک)</item>
<item quantity="one">ایک منٹ کیلئے (تک <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> منتخب کردہ</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"متفرقات"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
</resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 667be14..e90d921 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -40,7 +40,7 @@
<string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> soniya"</string>
<string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> soniya"</string>
<string name="untitled" msgid="4638956954852782576">"<Nomsiz>"</string>
- <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon raqamlari yo‘q)"</string>
+ <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Telefon raqami yo‘q)"</string>
<string name="unknownName" msgid="6867811765370350269">"Noma’lum"</string>
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Ovozli xabar"</string>
<string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
@@ -101,7 +101,7 @@
<string name="peerTtyModeHco" msgid="5728602160669216784">"Teng huquqli ishtirokchi teletayp rejimini HCO (eshitadi, gapirolmaydi) qilib o‘zgartirdi"</string>
<string name="peerTtyModeVco" msgid="1742404978686538049">"Teng huquqli ishtirokchi teletayp rejimini VCO (gapiradi, eshitolmaydi) qilib o‘zgartirdi"</string>
<string name="peerTtyModeOff" msgid="3280819717850602205">"Teng huquqli ishtirokchi teletayp rejimini OFF (o‘chirilgan) qilib o‘zgartirdi"</string>
- <string name="serviceClassVoice" msgid="1258393812335258019">"Ovoz"</string>
+ <string name="serviceClassVoice" msgid="1258393812335258019">"Ovozli aloqa"</string>
<string name="serviceClassData" msgid="872456782077937893">"Ma’lumot"</string>
<string name="serviceClassFAX" msgid="5566624998840486475">"FAKS"</string>
<string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
@@ -206,14 +206,14 @@
<string name="global_actions" product="tablet" msgid="408477140088053665">"Planshet sozlamalari"</string>
<string name="global_actions" product="tv" msgid="7240386462508182976">"TV tanlamalari"</string>
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefon sozlamalari"</string>
- <string name="global_action_lock" msgid="2844945191792119712">"Ekranni qulflash"</string>
+ <string name="global_action_lock" msgid="2844945191792119712">"Ekran qulfi"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
<string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
- <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Ovozsiz usul"</string>
+ <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Ovozsiz rejim"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Tovush o‘chirilgan"</string>
- <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Tovush yoqilgan"</string>
+ <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"YONIQ"</string>
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Parvoz rejimi"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Parvoz usuli yoqilgan"</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Parvoz rejimi o‘chirilgan"</string>
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Qulflash"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
<string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Shaxsiy"</string>
@@ -307,7 +308,7 @@
<string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"Ilova tizim qayta yoqilganidan so‘ng o‘zini ishga tushirishi mumkin. Bu planshetning yonish vaqtini uzaytirishi va doimiy ishlab turivchi ilova tufayli uning tezkor ishlashini kamaytirishi mumkin."</string>
<string name="permdesc_receiveBootCompleted" product="tv" msgid="4525890122209673621">"Ilovaga tizim ishga tushishi bilanoq o‘zi ham ishga tushadigan qilib qo‘yish huquqini beradi. Buning natijasida televizorning ishga tushishi sekinlashishi hamda ilovaning doimiy ravishda ishlab turishi oqibatida butun planshetning ishlashi sekinlashi mumkin."</string>
<string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"Ilova tizim qayta yoqilganidan so‘ng o‘zini ishga tushirishi mumkin. Bu telefonning yonish vaqtini uzaytirishi va doimiy ishlab turivchi ilova tufayli uning tezkor ishlashini kamaytirishi mumkin."</string>
- <string name="permlab_broadcastSticky" msgid="7919126372606881614">"yopishqoq radiouzatishlarni jo‘natish"</string>
+ <string name="permlab_broadcastSticky" msgid="7919126372606881614">"xabarlarni keyinchalik saqlash sharti bilan yuborish"</string>
<string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"Ilovaga uzatish tugagandan keyin ham qoladigan yopishqoq uzatishlarni jo‘natishga ruxsat beradi. Bu uzatishdan juda ko‘p foydalanish ko‘p xotiradan foydalanishga olib keladi va natijada planshet sekin yoki beqaror ishlashi mumkin."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Ilovaga efir tugagandan so‘ng ham saqlanib qoladigan turg‘un translatsiyalarni uzatish huquqini beradi. Undan ortiqcha foydalanish televizoringizni sekinlatishi yoki ko‘p xotira sarflaydigan qilib qo‘yishi mumkin."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Ilovaga uzatish tugagandan keyin ham qoladigan yopishqoq uzatishlarni jo‘natishga ruxsat beradi. Bu uzatishdan juda ko‘p foydalanish ko‘p xotiradan foydalanishga olib keladi va natijada telefon sekin yoki beqaror ishlashi mumkin."</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"tebranishni boshqarish"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ilova tebranishli signallarni boshqarishi mumkin."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"chiroq chaqnashini boshqarish"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ilova chaqnoqni boshqarishi mumkin."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS qo‘ng‘iroq xizmatiga kirish"</string>
@@ -375,7 +374,7 @@
<string name="permdesc_setWallpaper" msgid="7373447920977624745">"Ilova tizim uchun orqa fon rasmlarini o‘rnatishi mumkin."</string>
<string name="permlab_setWallpaperHints" msgid="3278608165977736538">"fon rasmi o‘lchamini moslash"</string>
<string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"Ilova tizimning orqa fon rasmlari uchun o‘lchamlarini ko‘rsatishi mumkin."</string>
- <string name="permlab_setTimeZone" msgid="2945079801013077340">"vaqt hududini o‘rnatish"</string>
+ <string name="permlab_setTimeZone" msgid="2945079801013077340">"vaqt mintaqasini sozlash"</string>
<string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"Iloba planshetdagi vaqt zonasini o‘zgartirishi mumkin."</string>
<string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Ilovaga televizorning vaqt zonasini o‘zgartirish huquqini beradi."</string>
<string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Ilova telefondagi vaqt zonasini o‘zgartirishi mumkin."</string>
@@ -702,7 +701,7 @@
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Qulfni ochish hisobi"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Qulfni ochish uchun Google hisobingiz bilan kiring."</string>
- <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Foydalanuvchi (e-pochta)"</string>
+ <string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Foydalanuvchi nomi (e-pochta)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Parol"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Kirish"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Foydalanuvchi nomi yoki paroli no‘to‘g‘ri."</string>
@@ -857,11 +856,14 @@
<string name="selectAll" msgid="6876518925844129331">"Barchasini tanlash"</string>
<string name="cut" msgid="3092569408438626261">"Kesish"</string>
<string name="copy" msgid="2681946229533511987">"Nusxa olish"</string>
- <string name="paste" msgid="5629880836805036433">"Qo‘yish"</string>
+ <string name="paste" msgid="5629880836805036433">"Joylash"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Oddiy matn sifatida joylash"</string>
<string name="replace" msgid="5781686059063148930">"Almashtirish"</string>
<string name="delete" msgid="6098684844021697789">"O‘chirish"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL’dan nusxa olish"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Matnni tanlash"</string>
+ <string name="undo" msgid="7905788502491742328">"Bekor qilish"</string>
+ <string name="redo" msgid="7759464876566803888">"Qaytarish"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Matni belgilash"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Lug‘atga qo‘shish"</string>
<string name="deleteText" msgid="6979668428458199034">"O‘chirish"</string>
@@ -937,11 +939,11 @@
<string name="dump_heap_title" msgid="5864292264307651673">"Hip-damp ma’lumotlari bilan ulashasizmi?"</string>
<string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> jarayoni o‘zi uchun ajratilgan <xliff:g id="SIZE">%2$s</xliff:g> xotira chegarasidan o‘tib ketdi. Ilova dasturchisi bilan ulashishingiz uchun hip-damp ma’lumotlari yig‘ilib qoldi. Ehtiyot bo\'ling: ushbu hip-dampda ilova uchun foydalanishga ruxsat berilgan shaxsiy ma’lumotlaringiz bo‘lishi mumkin."</string>
<string name="sendText" msgid="5209874571959469142">"Matn uchun amalni tanlash"</string>
- <string name="volume_ringtone" msgid="6885421406845734650">"Qo‘ng‘iroq tovushi"</string>
+ <string name="volume_ringtone" msgid="6885421406845734650">"Jiringlaganda ovoz balandligi"</string>
<string name="volume_music" msgid="5421651157138628171">"Multimedia ovozi"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth orqali ijro etilmoqda"</string>
<string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Ovozsiz rejim tanlandi"</string>
- <string name="volume_call" msgid="3941680041282788711">"Kiruvchi qo‘ng‘iroq balandligi"</string>
+ <string name="volume_call" msgid="3941680041282788711">"Suhbat vaqtidagi ovoz balandligi"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Kiruvchi bluetooth tovushi"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Signal ovozi"</string>
<string name="volume_notification" msgid="2422265656744276715">"Eslatma tovushi"</string>
@@ -992,7 +994,7 @@
<string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"Televizor <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulangan vaqtda Wi-Fi tarmog‘idan vaqtinchalik uziladi"</string>
<string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ga ulanganligi tufayli vaqtincha Wi-Fi tarmog‘idan uzildi."</string>
<string name="select_character" msgid="3365550120617701745">"Belgilarni kiriting"</string>
- <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar jo‘natilmoqda"</string>
+ <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
<string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"Ruxsat berish"</string>
<string name="sms_control_no" msgid="625438561395534982">"Rad qilish"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Fon rasmini o‘zgartirish"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Bildirishnoma tinglovchisi"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Shartlarni taqdim etuvchi"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Bildirishnoma yordamchisi"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN faollashtirildi"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN <xliff:g id="APP">%s</xliff:g> tomonidan faollashtirilgan"</string>
<string name="vpn_text" msgid="3011306607126450322">"Tarmoqni boshqarish uchun bosing."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Administratoringiz tomonidan yangilandi"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratoringiz tomonidan o‘chirilgan"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Bloklangan: bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Past: bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Oddiy: bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Yuqori: bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Shoshilinch: barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d daqiqa (<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g> gacha)</item>
<item quantity="one">Bir daqiqa (<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g> gacha)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta tanlandi</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Boshqa belgilar"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 49e14df..31e090b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Khóa ngay"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
<string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
<string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Cá nhân"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"kiểm soát rung"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Cho phép ứng dụng kiểm soát bộ rung."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Việc này có thể dẫn đến các khoản phí hoặc cuộc gọi không mong muốn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp. Các ứng dụng độc hại có thể khiến bạn tốn tiền do thực hiện cuộc gọi mà không cần sự xác nhận của bạn."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"truy cập dịch vụ gọi điện qua IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Cắt"</string>
<string name="copy" msgid="2681946229533511987">"Sao chép"</string>
<string name="paste" msgid="5629880836805036433">"Dán"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Dán dưới dạng văn bản thuần túy"</string>
<string name="replace" msgid="5781686059063148930">"Thay thế..."</string>
<string name="delete" msgid="6098684844021697789">"Xóa"</string>
<string name="copyUrl" msgid="2538211579596067402">"Sao chép URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Chọn văn bản"</string>
+ <string name="undo" msgid="7905788502491742328">"Hoàn tác"</string>
+ <string name="redo" msgid="7759464876566803888">"Làm lại"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Lựa chọn văn bản"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Thêm vào từ điển"</string>
<string name="deleteText" msgid="6979668428458199034">"Xóa"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Thay đổi hình nền"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Trình xử lý thông báo"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Trình cung cấp điều kiện"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Trợ lý thông báo"</string>
<string name="vpn_title" msgid="19615213552042827">"Đã kích hoạt VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN được <xliff:g id="APP">%s</xliff:g> kích hoạt"</string>
<string name="vpn_text" msgid="3011306607126450322">"Chạm để quản lý mạng."</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Được cập nhật bởi quản trị viên của bạn"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Đã bị xóa bởi quản trị viên của bạn"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"Mức độ quan trọng"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Đã chặn: Không bao giờ hiển thị các thông báo này"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Thấp: Hiển thị im lặng ở cuối danh sách thông báo"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Bình thường: Hiển thị im lặng các thông báo này"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Cao: Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Khẩn cấp: Hiển thị trên màn hình và phát ra âm thanh"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">Trong %1$d phút (cho đến <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">Trong một phút (cho đến <xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9492994..c5cd59a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"立即锁定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g> 条)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
<string name="user_owner_label" msgid="2804351898001038951">"个人"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允许应用控制振动器。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允许应用控制闪光灯。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允许该应用在您未执行操作的情况下拨打电话号码。此权限可能会导致意外收费或呼叫。请注意,此权限不允许该应用拨打紧急电话号码。恶意应用可通过拨打电话产生相关费用,而无需您的确认。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用即时通讯通话服务"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"剪切"</string>
<string name="copy" msgid="2681946229533511987">"复制"</string>
<string name="paste" msgid="5629880836805036433">"粘贴"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"以纯文本形式粘贴"</string>
<string name="replace" msgid="5781686059063148930">"替换..."</string>
<string name="delete" msgid="6098684844021697789">"删除"</string>
<string name="copyUrl" msgid="2538211579596067402">"复制网址"</string>
<string name="selectTextMode" msgid="1018691815143165326">"选择文字"</string>
+ <string name="undo" msgid="7905788502491742328">"撤消"</string>
+ <string name="redo" msgid="7759464876566803888">"重做"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"文字选择"</string>
<string name="addToDictionary" msgid="4352161534510057874">"添加到字典"</string>
<string name="deleteText" msgid="6979668428458199034">"删除"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"更改壁纸"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知侦听器"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"条件提供程序"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知助手"</string>
<string name="vpn_title" msgid="19615213552042827">"已激活VPN"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g>已激活VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"触摸可管理网络。"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"已被管理员删除"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"屏蔽:一律不显示这些通知"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"低:在通知列表底部显示,不发出提示音"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"一般:显示这些通知,但不发出提示音"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"高:在通知列表顶部显示,并发出提示音"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"紧急:在屏幕上持续显示,并发出提示音"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">%1$d 分钟(到<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">1 分钟(到<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"这些通知的重要性由您来设置。"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 0526580..36ba2ad6 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式繞過您自行撥打電話號碼,但可能會產生未預期的費用或撥打未預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能未經您確認擅自撥打電話,增加您的支出。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用 IMS 通話服務"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"剪下"</string>
<string name="copy" msgid="2681946229533511987">"複製"</string>
<string name="paste" msgid="5629880836805036433">"貼上"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"以純文字格式貼上"</string>
<string name="replace" msgid="5781686059063148930">"取代..."</string>
<string name="delete" msgid="6098684844021697789">"刪除"</string>
<string name="copyUrl" msgid="2538211579596067402">"複製網址"</string>
<string name="selectTextMode" msgid="1018691815143165326">"選取文字"</string>
+ <string name="undo" msgid="7905788502491742328">"復原"</string>
+ <string name="redo" msgid="7759464876566803888">"取消復原"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"選取文字"</string>
<string name="addToDictionary" msgid="4352161534510057874">"加入字典"</string>
<string name="deleteText" msgid="6979668428458199034">"刪除"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件供應商"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用。"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網絡。"</string>
@@ -1440,12 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"已由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"已由管理員刪除"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"節約電池用量模式有助於延長電池壽命,但這會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。除非您啟用,否則電郵、短訊及其他需要使用同步功能的應用程式均不會更新。\n\n當裝置充電時,節約電池用量模式會自動關閉。"</string>
- <string name="notification_importance_title" msgid="7493989722610008700">"重要性"</string>
- <string name="notification_importance_blocked" msgid="7118826900767047125">"已封鎖:永不顯示這些通知"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"低:以靜音方式顯示在通知清單底部"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"一般:以靜音方式顯示這些通知"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"高:顯示在通知清單頂部並發出音效"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"緊急:不時於螢幕出現並發出音效"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">需時 %1$d 分鐘 (完成時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">需時 1 分鐘 (完成時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,5 +1509,5 @@
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
<string name="importance_from_topic" msgid="3572280439880023233">"您可以為這些通知設定重要性。"</string>
- <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及使用者。"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 8a2d610..72ea523 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"立即鎖定"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"超過 999"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
<string name="user_owner_label" msgid="2804351898001038951">"個人"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加您不必要的額外支出。"</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"存取 IMS 撥號服務"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"剪下"</string>
<string name="copy" msgid="2681946229533511987">"複製"</string>
<string name="paste" msgid="5629880836805036433">"貼上"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"以純文字貼上"</string>
<string name="replace" msgid="5781686059063148930">"取代…"</string>
<string name="delete" msgid="6098684844021697789">"刪除"</string>
<string name="copyUrl" msgid="2538211579596067402">"複製網址"</string>
<string name="selectTextMode" msgid="1018691815143165326">"選取文字"</string>
+ <string name="undo" msgid="7905788502491742328">"復原"</string>
+ <string name="redo" msgid="7759464876566803888">"重做"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"選取文字"</string>
<string name="addToDictionary" msgid="4352161534510057874">"加入字典"</string>
<string name="deleteText" msgid="6979668428458199034">"刪除"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"變更桌布"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"通知接聽器"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"條件提供者"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"通知小幫手"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN 已啟用"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"<xliff:g id="APP">%s</xliff:g> 已啟用 VPN"</string>
<string name="vpn_text" msgid="3011306607126450322">"輕觸即可管理網路。"</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"由您的管理員更新"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"已遭管理員刪除"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"節約耗電量模式會透過降低裝置效能、震動限制、定位服務限制和大多數背景資料運作限制等方式,延長電池續航力。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當您為裝置充電時,節約耗電量模式會自動關閉。"</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"封鎖:一律不顯示這些通知"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"低:顯示在通知清單底部且不發出任何音效"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"一般:顯示這些通知且不發出任何音效"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"高:顯示在通知清單頂端並發出音效"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"緊急:持續顯示在螢幕上並發出音效"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="other">持續 %1$d 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="one">持續 1 分鐘 (結束時間:<xliff:g id="FORMATTEDTIME_0">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="one">已選取 <xliff:g id="COUNT_0">%1$d</xliff:g> 個項目</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"其他"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"這些通知的重要性由您決定。"</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 650ad33..bee7eea 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -223,6 +223,7 @@
<string name="global_action_lockdown" msgid="8751542514724332873">"Khiya manje"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
<string name="notification_children_count_bracketed" msgid="1769425473168347839">"(<xliff:g id="NOTIFICATIONCOUNT">%d</xliff:g>)"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
<string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
<string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
<string name="user_owner_label" msgid="2804351898001038951">"Okomuntu siqu"</string>
@@ -353,8 +354,6 @@
<string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
<string name="permlab_vibrate" msgid="7696427026057705834">"lawula ukudlidliza"</string>
<string name="permdesc_vibrate" msgid="6284989245902300945">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string>
- <string name="permlab_flashlight" msgid="2155920810121984215">"lawula ukukhanya kwefulashi"</string>
- <string name="permdesc_flashlight" msgid="6522284794568368310">"Ivumela uhlelo lokusebenza ukulawula ukukhanya kwefuleshi."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string>
<string name="permlab_accessImsCallService" msgid="3574943847181793918">"finyelela kusevisi yekholi ye-IMS"</string>
@@ -858,10 +857,13 @@
<string name="cut" msgid="3092569408438626261">"Nqamula"</string>
<string name="copy" msgid="2681946229533511987">"Kopisha"</string>
<string name="paste" msgid="5629880836805036433">"Namathisela"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"Namathisela njengombhalo osobala"</string>
<string name="replace" msgid="5781686059063148930">"Buyisela"</string>
<string name="delete" msgid="6098684844021697789">"Susa"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopisha i-URL"</string>
<string name="selectTextMode" msgid="1018691815143165326">"Khetha umbhalo"</string>
+ <string name="undo" msgid="7905788502491742328">"Hlehlisa"</string>
+ <string name="redo" msgid="7759464876566803888">"Yenza futhi"</string>
<string name="textSelectionCABTitle" msgid="5236850394370820357">"Inketho yombhalo"</string>
<string name="addToDictionary" msgid="4352161534510057874">"Engeza kwisichazamazwi"</string>
<string name="deleteText" msgid="6979668428458199034">"Susa"</string>
@@ -1107,6 +1109,7 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Shintsha iphephadonga"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"Umlaleli wesaziso"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"Umhlinzeki wesimo"</string>
+ <string name="notification_assistant_binding_label" msgid="909456055569102952">"Umsizi wesaziso"</string>
<string name="vpn_title" msgid="19615213552042827">"I-VPN isiyasebenza"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"i-VPN ivuswe ngu <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="3011306607126450322">"Thinta ukuze wengamele inethiwekhi."</string>
@@ -1440,13 +1443,6 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ibuyekezwe ngumqondisi wakho"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Isuswe ngumlawuli wakho"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
- <!-- no translation found for notification_importance_title (7493989722610008700) -->
- <skip />
- <string name="notification_importance_blocked" msgid="7118826900767047125">"Okuvinjiwe: Ungalokothi ubonise lezi zaziso"</string>
- <string name="notification_importance_low" msgid="6447640449918427187">"Okuphansi: Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
- <string name="notification_importance_default" msgid="7991157697609575271">"Okujwayelekile: Bonisa ngokuthulile lezi zaziso"</string>
- <string name="notification_importance_high" msgid="3152238637737215654">"Okuphezulu: Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
- <string name="notification_importance_max" msgid="1153693080467904474">"Okuphuthumayo: Bheka kusikrini uphinde wenze umsindo"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
<item quantity="one">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">Okwamaminithi angu-%1$d (kuze kube ngo-<xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1512,8 +1508,6 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> okukhethiwe</item>
</plurals>
<string name="default_notification_topic_label" msgid="227586145791870829">"Okwahlukahlukene"</string>
- <!-- no translation found for importance_from_topic (3572280439880023233) -->
- <skip />
- <!-- no translation found for importance_from_person (9160133597262938296) -->
- <skip />
+ <string name="importance_from_topic" msgid="3572280439880023233">"Usethe ukubaluleka kwalezi zaziso."</string>
+ <string name="importance_from_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2a11081..58a77e8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1857,6 +1857,11 @@
<attr name="lockTaskMode" />
<attr name="showForAllUsers" />
<attr name="encryptionAware" />
+ <!-- @hide This activity is always focusable regardless of if it is in a task/stack whose
+ activities are normally not focusable.
+ For example, {@link android.R.attr#supportsPictureInPicture} activities are placed
+ in a task/stack that isn't focusable. This flag allows them to be focusable.-->
+ <attr name="alwaysFocusable" format="boolean" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index bff8b1a..d13a622 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2370,7 +2370,7 @@
<!-- Set initial MaxRetry value for operators -->
<integer name="config_mdc_initial_max_retry">1</integer>
- <!-- The OEM specified sensor type for the gesture to launch the camear app. -->
+ <!-- The OEM specified sensor type for the gesture to launch the camera app. -->
<integer name="config_cameraLaunchGestureSensorType">-1</integer>
<!-- The OEM specified sensor string type for the gesture to launch camera app, this value
must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
@@ -2407,4 +2407,14 @@
that have not requested doing so (via the WindowManager.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
flag). -->
<bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
+
+ <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
+ <string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
+
+ <!-- Controls the snap mode for the docked stack divider
+ 0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
+ 1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+ 2 - 1 snap target: 1:1
+ -->
+ <integer name="config_dockedStackDividerSnapMode">0</integer>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b167711..37b2c12 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -47,7 +47,7 @@
<!-- How much the content in the divider is inset from the window bounds when resting. Used to
calculate the bounds of the stacks-->
- <dimen name="docked_stack_divider_insets">18dp</dimen>
+ <dimen name="docked_stack_divider_insets">19dp</dimen>
<!-- Min width for a tablet device -->
<dimen name="min_xlarge_screen_width">800dp</dimen>
@@ -142,6 +142,9 @@
<!-- height of the content margin to accomodate for the header -->
<dimen name="notification_content_margin_top">30dp</dimen>
+ <!-- height of the content margin on the bottom -->
+ <dimen name="notification_content_margin_bottom">13dp</dimen>
+
<!-- height of notification header view if present -->
<dimen name="notification_header_height">32dp</dimen>
@@ -153,14 +156,11 @@
<!-- The width of the big icons in notifications. -->
<dimen name="notification_large_icon_height">64dp</dimen>
- <!-- Min height of the notification content. -->
- <dimen name="notification_min_content_height">54dp</dimen>
-
<!-- The minimum width of the app name in the header if it shrinks -->
<dimen name="notification_header_shrink_min_width">72dp</dimen>
- <!-- The minimum height of the content if there is a picture present with big picture -->
- <dimen name="notification_big_picture_content_min_height_with_picture">41dp</dimen>
+ <!-- The minimum height of the content if there are at least two lines or a picture-->
+ <dimen name="notification_min_content_height">41dp</dimen>
<!-- Preferred width of the search view. -->
<dimen name="search_view_preferred_width">320dip</dimen>
@@ -429,4 +429,6 @@
<item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
<item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+ <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
</resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
new file mode 100644
index 0000000..3cfd9f4
--- /dev/null
+++ b/core/res/res/values/locale_config.xml
@@ -0,0 +1,499 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+
+ <string-array translatable="false" name="supported_locales">
+ <item>af-NA</item> <!-- Afrikaans (Namibia) -->
+ <item>af-ZA</item> <!-- Afrikaans (South Africa) -->
+ <item>agq-CM</item> <!-- Aghem (Cameroon) -->
+ <item>ak-GH</item> <!-- Akan (Ghana) -->
+ <item>am-ET</item> <!-- Amharic (Ethiopia) -->
+ <item>ar-AE</item> <!-- Arabic (United Arab Emirates) -->
+ <item>ar-BH</item> <!-- Arabic (Bahrain) -->
+ <item>ar-DJ</item> <!-- Arabic (Djibouti) -->
+ <item>ar-DZ</item> <!-- Arabic (Algeria) -->
+ <item>ar-EG</item> <!-- Arabic (Egypt) -->
+ <item>ar-EH</item> <!-- Arabic (Western Sahara) -->
+ <item>ar-ER</item> <!-- Arabic (Eritrea) -->
+ <item>ar-IL</item> <!-- Arabic (Israel) -->
+ <item>ar-IQ</item> <!-- Arabic (Iraq) -->
+ <item>ar-JO</item> <!-- Arabic (Jordan) -->
+ <item>ar-KM</item> <!-- Arabic (Comoros) -->
+ <item>ar-KW</item> <!-- Arabic (Kuwait) -->
+ <item>ar-LB</item> <!-- Arabic (Lebanon) -->
+ <item>ar-LY</item> <!-- Arabic (Libya) -->
+ <item>ar-MA</item> <!-- Arabic (Morocco) -->
+ <item>ar-MR</item> <!-- Arabic (Mauritania) -->
+ <item>ar-OM</item> <!-- Arabic (Oman) -->
+ <item>ar-PS</item> <!-- Arabic (Palestine) -->
+ <item>ar-QA</item> <!-- Arabic (Qatar) -->
+ <item>ar-SA</item> <!-- Arabic (Saudi Arabia) -->
+ <item>ar-SD</item> <!-- Arabic (Sudan) -->
+ <item>ar-SO</item> <!-- Arabic (Somalia) -->
+ <item>ar-SS</item> <!-- Arabic (South Sudan) -->
+ <item>ar-SY</item> <!-- Arabic (Syria) -->
+ <item>ar-TD</item> <!-- Arabic (Chad) -->
+ <item>ar-TN</item> <!-- Arabic (Tunisia) -->
+ <item>ar-XB</item> <!-- Right-to-left pseudolocale -->
+ <item>ar-YE</item> <!-- Arabic (Yemen) -->
+ <item>as-IN</item> <!-- Assamese (India) -->
+ <item>asa-TZ</item> <!-- Asu (Tanzania) -->
+ <item>az-Cyrl-AZ</item> <!-- Azerbaijani (Cyrillic,Azerbaijan) -->
+ <item>az-Latn-AZ</item> <!-- Azerbaijani (Latin,Azerbaijan) -->
+ <item>bas-CM</item> <!-- Basaa (Cameroon) -->
+ <item>be-BY</item> <!-- Belarusian (Belarus) -->
+ <item>bem-ZM</item> <!-- Bemba (Zambia) -->
+ <item>bez-TZ</item> <!-- Bena (Tanzania) -->
+ <item>bg-BG</item> <!-- Bulgarian (Bulgaria) -->
+ <item>bm-ML</item> <!-- Bambara (Mali) -->
+ <item>bn-BD</item> <!-- Bengali (Bangladesh) -->
+ <item>bn-IN</item> <!-- Bengali (India) -->
+ <item>bo-CN</item> <!-- Tibetan (China) -->
+ <item>bo-IN</item> <!-- Tibetan (India) -->
+ <item>br-FR</item> <!-- Breton (France) -->
+ <item>brx-IN</item> <!-- Bodo (India) -->
+ <item>bs-Cyrl-BA</item> <!-- Bosnian (Cyrillic,Bosnia & Herzegovina) -->
+ <item>bs-Latn-BA</item> <!-- Bosnian (Latin,Bosnia & Herzegovina) -->
+ <item>ca-AD</item> <!-- Catalan (Andorra) -->
+ <item>ca-ES</item> <!-- Catalan (Spain) -->
+ <item>ca-FR</item> <!-- Catalan (France) -->
+ <item>ca-IT</item> <!-- Catalan (Italy) -->
+ <item>ce-RU</item> <!-- Chechen (Russia) -->
+ <item>cgg-UG</item> <!-- Chiga (Uganda) -->
+ <item>chr-US</item> <!-- Cherokee (United States) -->
+ <item>cs-CZ</item> <!-- Czech (Czech Republic) -->
+ <item>cy-GB</item> <!-- Welsh (United Kingdom) -->
+ <item>da-DK</item> <!-- Danish (Denmark) -->
+ <item>da-GL</item> <!-- Danish (Greenland) -->
+ <item>dav-KE</item> <!-- Taita (Kenya) -->
+ <item>de-AT</item> <!-- German (Austria) -->
+ <item>de-BE</item> <!-- German (Belgium) -->
+ <item>de-CH</item> <!-- German (Switzerland) -->
+ <item>de-DE</item> <!-- German (Germany) -->
+ <item>de-LI</item> <!-- German (Liechtenstein) -->
+ <item>de-LU</item> <!-- German (Luxembourg) -->
+ <item>dje-NE</item> <!-- Zarma (Niger) -->
+ <item>dsb-DE</item> <!-- Lower Sorbian (Germany) -->
+ <item>dua-CM</item> <!-- Duala (Cameroon) -->
+ <item>dyo-SN</item> <!-- Jola-Fonyi (Senegal) -->
+ <item>dz-BT</item> <!-- Dzongkha (Bhutan) -->
+ <item>ebu-KE</item> <!-- Embu (Kenya) -->
+ <item>ee-GH</item> <!-- Ewe (Ghana) -->
+ <item>ee-TG</item> <!-- Ewe (Togo) -->
+ <item>el-CY</item> <!-- Greek (Cyprus) -->
+ <item>el-GR</item> <!-- Greek (Greece) -->
+ <item>en-AG</item> <!-- English (Antigua & Barbuda) -->
+ <item>en-AI</item> <!-- English (Anguilla) -->
+ <item>en-AS</item> <!-- English (American Samoa) -->
+ <item>en-AT</item> <!-- English (Austria) -->
+ <item>en-AU</item> <!-- English (Australia) -->
+ <item>en-BB</item> <!-- English (Barbados) -->
+ <item>en-BE</item> <!-- English (Belgium) -->
+ <item>en-BI</item> <!-- English (Burundi) -->
+ <item>en-BM</item> <!-- English (Bermuda) -->
+ <item>en-BS</item> <!-- English (Bahamas) -->
+ <item>en-BW</item> <!-- English (Botswana) -->
+ <item>en-BZ</item> <!-- English (Belize) -->
+ <item>en-CA</item> <!-- English (Canada) -->
+ <item>en-CC</item> <!-- English (Cocos (Keeling) Islands) -->
+ <item>en-CH</item> <!-- English (Switzerland) -->
+ <item>en-CK</item> <!-- English (Cook Islands) -->
+ <item>en-CM</item> <!-- English (Cameroon) -->
+ <item>en-CX</item> <!-- English (Christmas Island) -->
+ <item>en-CY</item> <!-- English (Cyprus) -->
+ <item>en-DE</item> <!-- English (Germany) -->
+ <item>en-DG</item> <!-- English (Diego Garcia) -->
+ <item>en-DK</item> <!-- English (Denmark) -->
+ <item>en-DM</item> <!-- English (Dominica) -->
+ <item>en-ER</item> <!-- English (Eritrea) -->
+ <item>en-FI</item> <!-- English (Finland) -->
+ <item>en-FJ</item> <!-- English (Fiji) -->
+ <item>en-FK</item> <!-- English (Falkland Islands (Islas Malvinas)) -->
+ <item>en-FM</item> <!-- English (Micronesia) -->
+ <item>en-GB</item> <!-- English (United Kingdom) -->
+ <item>en-GD</item> <!-- English (Grenada) -->
+ <item>en-GG</item> <!-- English (Guernsey) -->
+ <item>en-GH</item> <!-- English (Ghana) -->
+ <item>en-GI</item> <!-- English (Gibraltar) -->
+ <item>en-GM</item> <!-- English (Gambia) -->
+ <item>en-GU</item> <!-- English (Guam) -->
+ <item>en-GY</item> <!-- English (Guyana) -->
+ <item>en-HK</item> <!-- English (Hong Kong) -->
+ <item>en-IE</item> <!-- English (Ireland) -->
+ <item>en-IL</item> <!-- English (Israel) -->
+ <item>en-IM</item> <!-- English (Isle of Man) -->
+ <item>en-IN</item> <!-- English (India) -->
+ <item>en-IO</item> <!-- English (British Indian Ocean Territory) -->
+ <item>en-JE</item> <!-- English (Jersey) -->
+ <item>en-JM</item> <!-- English (Jamaica) -->
+ <item>en-KE</item> <!-- English (Kenya) -->
+ <item>en-KI</item> <!-- English (Kiribati) -->
+ <item>en-KN</item> <!-- English (St. Kitts & Nevis) -->
+ <item>en-KY</item> <!-- English (Cayman Islands) -->
+ <item>en-LC</item> <!-- English (St. Lucia) -->
+ <item>en-LR</item> <!-- English (Liberia) -->
+ <item>en-LS</item> <!-- English (Lesotho) -->
+ <item>en-MG</item> <!-- English (Madagascar) -->
+ <item>en-MH</item> <!-- English (Marshall Islands) -->
+ <item>en-MO</item> <!-- English (Macau) -->
+ <item>en-MP</item> <!-- English (Northern Mariana Islands) -->
+ <item>en-MS</item> <!-- English (Montserrat) -->
+ <item>en-MT</item> <!-- English (Malta) -->
+ <item>en-MU</item> <!-- English (Mauritius) -->
+ <item>en-MW</item> <!-- English (Malawi) -->
+ <item>en-MY</item> <!-- English (Malaysia) -->
+ <item>en-NA</item> <!-- English (Namibia) -->
+ <item>en-NF</item> <!-- English (Norfolk Island) -->
+ <item>en-NG</item> <!-- English (Nigeria) -->
+ <item>en-NL</item> <!-- English (Netherlands) -->
+ <item>en-NR</item> <!-- English (Nauru) -->
+ <item>en-NU</item> <!-- English (Niue) -->
+ <item>en-NZ</item> <!-- English (New Zealand) -->
+ <item>en-PG</item> <!-- English (Papua New Guinea) -->
+ <item>en-PH</item> <!-- English (Philippines) -->
+ <item>en-PK</item> <!-- English (Pakistan) -->
+ <item>en-PN</item> <!-- English (Pitcairn Islands) -->
+ <item>en-PR</item> <!-- English (Puerto Rico) -->
+ <item>en-PW</item> <!-- English (Palau) -->
+ <item>en-RW</item> <!-- English (Rwanda) -->
+ <item>en-SB</item> <!-- English (Solomon Islands) -->
+ <item>en-SC</item> <!-- English (Seychelles) -->
+ <item>en-SD</item> <!-- English (Sudan) -->
+ <item>en-SE</item> <!-- English (Sweden) -->
+ <item>en-SG</item> <!-- English (Singapore) -->
+ <item>en-SH</item> <!-- English (St. Helena) -->
+ <item>en-SI</item> <!-- English (Slovenia) -->
+ <item>en-SL</item> <!-- English (Sierra Leone) -->
+ <item>en-SS</item> <!-- English (South Sudan) -->
+ <item>en-SX</item> <!-- English (Sint Maarten) -->
+ <item>en-SZ</item> <!-- English (Swaziland) -->
+ <item>en-TC</item> <!-- English (Turks & Caicos Islands) -->
+ <item>en-TK</item> <!-- English (Tokelau) -->
+ <item>en-TO</item> <!-- English (Tonga) -->
+ <item>en-TT</item> <!-- English (Trinidad & Tobago) -->
+ <item>en-TV</item> <!-- English (Tuvalu) -->
+ <item>en-TZ</item> <!-- English (Tanzania) -->
+ <item>en-UG</item> <!-- English (Uganda) -->
+ <item>en-UM</item> <!-- English (U.S. Outlying Islands) -->
+ <item>en-US</item> <!-- English (United States) -->
+ <item>en-VC</item> <!-- English (St. Vincent & Grenadines) -->
+ <item>en-VG</item> <!-- English (British Virgin Islands) -->
+ <item>en-VI</item> <!-- English (U.S. Virgin Islands) -->
+ <item>en-VU</item> <!-- English (Vanuatu) -->
+ <item>en-WS</item> <!-- English (Samoa) -->
+ <item>en-XA</item> <!-- Left-to-right pseudolocale -->
+ <item>en-ZA</item> <!-- English (South Africa) -->
+ <item>en-ZM</item> <!-- English (Zambia) -->
+ <item>en-ZW</item> <!-- English (Zimbabwe) -->
+ <item>es-AR</item> <!-- Spanish (Argentina) -->
+ <item>es-BO</item> <!-- Spanish (Bolivia) -->
+ <item>es-CL</item> <!-- Spanish (Chile) -->
+ <item>es-CO</item> <!-- Spanish (Colombia) -->
+ <item>es-CR</item> <!-- Spanish (Costa Rica) -->
+ <item>es-CU</item> <!-- Spanish (Cuba) -->
+ <item>es-DO</item> <!-- Spanish (Dominican Republic) -->
+ <item>es-EA</item> <!-- Spanish (Ceuta & Melilla) -->
+ <item>es-EC</item> <!-- Spanish (Ecuador) -->
+ <item>es-ES</item> <!-- Spanish (Spain) -->
+ <item>es-GQ</item> <!-- Spanish (Equatorial Guinea) -->
+ <item>es-GT</item> <!-- Spanish (Guatemala) -->
+ <item>es-HN</item> <!-- Spanish (Honduras) -->
+ <item>es-IC</item> <!-- Spanish (Canary Islands) -->
+ <item>es-MX</item> <!-- Spanish (Mexico) -->
+ <item>es-NI</item> <!-- Spanish (Nicaragua) -->
+ <item>es-PA</item> <!-- Spanish (Panama) -->
+ <item>es-PE</item> <!-- Spanish (Peru) -->
+ <item>es-PH</item> <!-- Spanish (Philippines) -->
+ <item>es-PR</item> <!-- Spanish (Puerto Rico) -->
+ <item>es-PY</item> <!-- Spanish (Paraguay) -->
+ <item>es-SV</item> <!-- Spanish (El Salvador) -->
+ <item>es-US</item> <!-- Spanish (United States) -->
+ <item>es-UY</item> <!-- Spanish (Uruguay) -->
+ <item>es-VE</item> <!-- Spanish (Venezuela) -->
+ <item>et-EE</item> <!-- Estonian (Estonia) -->
+ <item>eu-ES</item> <!-- Basque (Spain) -->
+ <item>ewo-CM</item> <!-- Ewondo (Cameroon) -->
+ <item>fa-AF</item> <!-- Persian (Afghanistan) -->
+ <item>fa-IR</item> <!-- Persian (Iran) -->
+ <item>ff-CM</item> <!-- Fulah (Cameroon) -->
+ <item>ff-GN</item> <!-- Fulah (Guinea) -->
+ <item>ff-MR</item> <!-- Fulah (Mauritania) -->
+ <item>ff-SN</item> <!-- Fulah (Senegal) -->
+ <item>fi-FI</item> <!-- Finnish (Finland) -->
+ <item>fil-PH</item> <!-- Filipino (Philippines) -->
+ <item>fo-DK</item> <!-- Faroese (Denmark) -->
+ <item>fo-FO</item> <!-- Faroese (Faroe Islands) -->
+ <item>fr-BE</item> <!-- French (Belgium) -->
+ <item>fr-BF</item> <!-- French (Burkina Faso) -->
+ <item>fr-BI</item> <!-- French (Burundi) -->
+ <item>fr-BJ</item> <!-- French (Benin) -->
+ <item>fr-BL</item> <!-- French (St. Barthélemy) -->
+ <item>fr-CA</item> <!-- French (Canada) -->
+ <item>fr-CD</item> <!-- French (Congo (DRC)) -->
+ <item>fr-CF</item> <!-- French (Central African Republic) -->
+ <item>fr-CG</item> <!-- French (Congo (Republic)) -->
+ <item>fr-CH</item> <!-- French (Switzerland) -->
+ <item>fr-CI</item> <!-- French (Côte d’Ivoire) -->
+ <item>fr-CM</item> <!-- French (Cameroon) -->
+ <item>fr-DJ</item> <!-- French (Djibouti) -->
+ <item>fr-DZ</item> <!-- French (Algeria) -->
+ <item>fr-FR</item> <!-- French (France) -->
+ <item>fr-GA</item> <!-- French (Gabon) -->
+ <item>fr-GF</item> <!-- French (French Guiana) -->
+ <item>fr-GN</item> <!-- French (Guinea) -->
+ <item>fr-GP</item> <!-- French (Guadeloupe) -->
+ <item>fr-GQ</item> <!-- French (Equatorial Guinea) -->
+ <item>fr-HT</item> <!-- French (Haiti) -->
+ <item>fr-KM</item> <!-- French (Comoros) -->
+ <item>fr-LU</item> <!-- French (Luxembourg) -->
+ <item>fr-MA</item> <!-- French (Morocco) -->
+ <item>fr-MC</item> <!-- French (Monaco) -->
+ <item>fr-MF</item> <!-- French (St. Martin) -->
+ <item>fr-MG</item> <!-- French (Madagascar) -->
+ <item>fr-ML</item> <!-- French (Mali) -->
+ <item>fr-MQ</item> <!-- French (Martinique) -->
+ <item>fr-MR</item> <!-- French (Mauritania) -->
+ <item>fr-MU</item> <!-- French (Mauritius) -->
+ <item>fr-NC</item> <!-- French (New Caledonia) -->
+ <item>fr-NE</item> <!-- French (Niger) -->
+ <item>fr-PF</item> <!-- French (French Polynesia) -->
+ <item>fr-PM</item> <!-- French (St. Pierre & Miquelon) -->
+ <item>fr-RE</item> <!-- French (Réunion) -->
+ <item>fr-RW</item> <!-- French (Rwanda) -->
+ <item>fr-SC</item> <!-- French (Seychelles) -->
+ <item>fr-SN</item> <!-- French (Senegal) -->
+ <item>fr-SY</item> <!-- French (Syria) -->
+ <item>fr-TD</item> <!-- French (Chad) -->
+ <item>fr-TG</item> <!-- French (Togo) -->
+ <item>fr-TN</item> <!-- French (Tunisia) -->
+ <item>fr-VU</item> <!-- French (Vanuatu) -->
+ <item>fr-WF</item> <!-- French (Wallis & Futuna) -->
+ <item>fr-YT</item> <!-- French (Mayotte) -->
+ <item>fur-IT</item> <!-- Friulian (Italy) -->
+ <item>fy-NL</item> <!-- Western Frisian (Netherlands) -->
+ <item>ga-IE</item> <!-- Irish (Ireland) -->
+ <item>gd-GB</item> <!-- Scottish Gaelic (United Kingdom) -->
+ <item>gl-ES</item> <!-- Galician (Spain) -->
+ <item>gsw-CH</item> <!-- Swiss German (Switzerland) -->
+ <item>gsw-FR</item> <!-- Swiss German (France) -->
+ <item>gsw-LI</item> <!-- Swiss German (Liechtenstein) -->
+ <item>gu-IN</item> <!-- Gujarati (India) -->
+ <item>guz-KE</item> <!-- Gusii (Kenya) -->
+ <item>gv-IM</item> <!-- Manx (Isle of Man) -->
+ <item>ha-GH</item> <!-- Hausa (Ghana) -->
+ <item>ha-NE</item> <!-- Hausa (Niger) -->
+ <item>ha-NG</item> <!-- Hausa (Nigeria) -->
+ <item>haw-US</item> <!-- Hawaiian (United States) -->
+ <item>iw-IL</item> <!-- Hebrew (Israel) -->
+ <item>hi-IN</item> <!-- Hindi (India) -->
+ <item>hr-BA</item> <!-- Croatian (Bosnia & Herzegovina) -->
+ <item>hr-HR</item> <!-- Croatian (Croatia) -->
+ <item>hsb-DE</item> <!-- Upper Sorbian (Germany) -->
+ <item>hu-HU</item> <!-- Hungarian (Hungary) -->
+ <item>hy-AM</item> <!-- Armenian (Armenia) -->
+ <item>in-ID</item> <!-- Indonesian (Indonesia) -->
+ <item>ig-NG</item> <!-- Igbo (Nigeria) -->
+ <item>ii-CN</item> <!-- Sichuan Yi (China) -->
+ <item>is-IS</item> <!-- Icelandic (Iceland) -->
+ <item>it-CH</item> <!-- Italian (Switzerland) -->
+ <item>it-IT</item> <!-- Italian (Italy) -->
+ <item>it-SM</item> <!-- Italian (San Marino) -->
+ <item>ja-JP</item> <!-- Japanese (Japan) -->
+ <item>jgo-CM</item> <!-- Ngomba (Cameroon) -->
+ <item>jmc-TZ</item> <!-- Machame (Tanzania) -->
+ <item>ka-GE</item> <!-- Georgian (Georgia) -->
+ <item>kab-DZ</item> <!-- Kabyle (Algeria) -->
+ <item>kam-KE</item> <!-- Kamba (Kenya) -->
+ <item>kde-TZ</item> <!-- Makonde (Tanzania) -->
+ <item>kea-CV</item> <!-- Kabuverdianu (Cape Verde) -->
+ <item>khq-ML</item> <!-- Koyra Chiini (Mali) -->
+ <item>ki-KE</item> <!-- Kikuyu (Kenya) -->
+ <item>kk-KZ</item> <!-- Kazakh (Kazakhstan) -->
+ <item>kkj-CM</item> <!-- Kako (Cameroon) -->
+ <item>kl-GL</item> <!-- Kalaallisut (Greenland) -->
+ <item>kln-KE</item> <!-- Kalenjin (Kenya) -->
+ <item>km-KH</item> <!-- Khmer (Cambodia) -->
+ <item>kn-IN</item> <!-- Kannada (India) -->
+ <item>ko-KP</item> <!-- Korean (North Korea) -->
+ <item>ko-KR</item> <!-- Korean (South Korea) -->
+ <item>kok-IN</item> <!-- Konkani (India) -->
+ <item>ksb-TZ</item> <!-- Shambala (Tanzania) -->
+ <item>ksf-CM</item> <!-- Bafia (Cameroon) -->
+ <item>ksh-DE</item> <!-- Colognian (Germany) -->
+ <item>kw-GB</item> <!-- Cornish (United Kingdom) -->
+ <item>ky-KG</item> <!-- Kyrgyz (Kyrgyzstan) -->
+ <item>lag-TZ</item> <!-- Langi (Tanzania) -->
+ <item>lb-LU</item> <!-- Luxembourgish (Luxembourg) -->
+ <item>lg-UG</item> <!-- Ganda (Uganda) -->
+ <item>lkt-US</item> <!-- Lakota (United States) -->
+ <item>ln-AO</item> <!-- Lingala (Angola) -->
+ <item>ln-CD</item> <!-- Lingala (Congo (DRC)) -->
+ <item>ln-CF</item> <!-- Lingala (Central African Republic) -->
+ <item>ln-CG</item> <!-- Lingala (Congo (Republic)) -->
+ <item>lo-LA</item> <!-- Lao (Laos) -->
+ <item>lt-LT</item> <!-- Lithuanian (Lithuania) -->
+ <item>lu-CD</item> <!-- Luba-Katanga (Congo (DRC)) -->
+ <item>luo-KE</item> <!-- Luo (Kenya) -->
+ <item>luy-KE</item> <!-- Luyia (Kenya) -->
+ <item>lv-LV</item> <!-- Latvian (Latvia) -->
+ <item>mas-KE</item> <!-- Masai (Kenya) -->
+ <item>mas-TZ</item> <!-- Masai (Tanzania) -->
+ <item>mer-KE</item> <!-- Meru (Kenya) -->
+ <item>mfe-MU</item> <!-- Morisyen (Mauritius) -->
+ <item>mg-MG</item> <!-- Malagasy (Madagascar) -->
+ <item>mgh-MZ</item> <!-- Makhuwa-Meetto (Mozambique) -->
+ <item>mgo-CM</item> <!-- Metaʼ (Cameroon) -->
+ <item>mk-MK</item> <!-- Macedonian (Macedonia (FYROM)) -->
+ <item>ml-IN</item> <!-- Malayalam (India) -->
+ <item>mn-MN</item> <!-- Mongolian (Mongolia) -->
+ <item>mr-IN</item> <!-- Marathi (India) -->
+ <item>ms-BN</item> <!-- Malay (Brunei) -->
+ <item>ms-MY</item> <!-- Malay (Malaysia) -->
+ <item>ms-SG</item> <!-- Malay (Singapore) -->
+ <item>mt-MT</item> <!-- Maltese (Malta) -->
+ <item>my-MM</item> <!-- Burmese (Myanmar (Burma)) -->
+ <item>mzn-IR</item> <!-- Mazanderani (Iran) -->
+ <item>naq-NA</item> <!-- Nama (Namibia) -->
+ <item>nb-NO</item> <!-- Norwegian Bokmål (Norway) -->
+ <item>nb-SJ</item> <!-- Norwegian Bokmål (Svalbard & Jan Mayen) -->
+ <item>nd-ZW</item> <!-- North Ndebele (Zimbabwe) -->
+ <item>ne-IN</item> <!-- Nepali (India) -->
+ <item>ne-NP</item> <!-- Nepali (Nepal) -->
+ <item>nl-AW</item> <!-- Dutch (Aruba) -->
+ <item>nl-BE</item> <!-- Dutch (Belgium) -->
+ <item>nl-BQ</item> <!-- Dutch (Caribbean Netherlands) -->
+ <item>nl-CW</item> <!-- Dutch (Curaçao) -->
+ <item>nl-NL</item> <!-- Dutch (Netherlands) -->
+ <item>nl-SR</item> <!-- Dutch (Suriname) -->
+ <item>nl-SX</item> <!-- Dutch (Sint Maarten) -->
+ <item>nmg-CM</item> <!-- Kwasio (Cameroon) -->
+ <item>nn-NO</item> <!-- Norwegian Nynorsk (Norway) -->
+ <item>nnh-CM</item> <!-- Ngiemboon (Cameroon) -->
+ <item>nus-SS</item> <!-- Nuer (South Sudan) -->
+ <item>nyn-UG</item> <!-- Nyankole (Uganda) -->
+ <item>om-ET</item> <!-- Oromo (Ethiopia) -->
+ <item>om-KE</item> <!-- Oromo (Kenya) -->
+ <item>or-IN</item> <!-- Oriya (India) -->
+ <item>os-GE</item> <!-- Ossetic (Georgia) -->
+ <item>os-RU</item> <!-- Ossetic (Russia) -->
+ <item>pa-Arab-PK</item> <!-- Punjabi (Arabic,Pakistan) -->
+ <item>pa-Guru-IN</item> <!-- Punjabi (Gurmukhi,India) -->
+ <item>pl-PL</item> <!-- Polish (Poland) -->
+ <item>ps-AF</item> <!-- Pashto (Afghanistan) -->
+ <item>pt-AO</item> <!-- Portuguese (Angola) -->
+ <item>pt-BR</item> <!-- Portuguese (Brazil) -->
+ <item>pt-CV</item> <!-- Portuguese (Cape Verde) -->
+ <item>pt-GW</item> <!-- Portuguese (Guinea-Bissau) -->
+ <item>pt-MO</item> <!-- Portuguese (Macau) -->
+ <item>pt-MZ</item> <!-- Portuguese (Mozambique) -->
+ <item>pt-PT</item> <!-- Portuguese (Portugal) -->
+ <item>pt-ST</item> <!-- Portuguese (São Tomé & Príncipe) -->
+ <item>pt-TL</item> <!-- Portuguese (Timor-Leste) -->
+ <item>qu-BO</item> <!-- Quechua (Bolivia) -->
+ <item>qu-EC</item> <!-- Quechua (Ecuador) -->
+ <item>qu-PE</item> <!-- Quechua (Peru) -->
+ <item>rm-CH</item> <!-- Romansh (Switzerland) -->
+ <item>rn-BI</item> <!-- Rundi (Burundi) -->
+ <item>ro-MD</item> <!-- Romanian (Moldova) -->
+ <item>ro-RO</item> <!-- Romanian (Romania) -->
+ <item>rof-TZ</item> <!-- Rombo (Tanzania) -->
+ <item>ru-BY</item> <!-- Russian (Belarus) -->
+ <item>ru-KG</item> <!-- Russian (Kyrgyzstan) -->
+ <item>ru-KZ</item> <!-- Russian (Kazakhstan) -->
+ <item>ru-MD</item> <!-- Russian (Moldova) -->
+ <item>ru-RU</item> <!-- Russian (Russia) -->
+ <item>ru-UA</item> <!-- Russian (Ukraine) -->
+ <item>rw-RW</item> <!-- Kinyarwanda (Rwanda) -->
+ <item>rwk-TZ</item> <!-- Rwa (Tanzania) -->
+ <item>sah-RU</item> <!-- Sakha (Russia) -->
+ <item>saq-KE</item> <!-- Samburu (Kenya) -->
+ <item>sbp-TZ</item> <!-- Sangu (Tanzania) -->
+ <item>se-FI</item> <!-- Northern Sami (Finland) -->
+ <item>se-NO</item> <!-- Northern Sami (Norway) -->
+ <item>se-SE</item> <!-- Northern Sami (Sweden) -->
+ <item>seh-MZ</item> <!-- Sena (Mozambique) -->
+ <item>ses-ML</item> <!-- Koyraboro Senni (Mali) -->
+ <item>sg-CF</item> <!-- Sango (Central African Republic) -->
+ <item>si-LK</item> <!-- Sinhala (Sri Lanka) -->
+ <item>sk-SK</item> <!-- Slovak (Slovakia) -->
+ <item>sl-SI</item> <!-- Slovenian (Slovenia) -->
+ <item>smn-FI</item> <!-- Inari Sami (Finland) -->
+ <item>sn-ZW</item> <!-- Shona (Zimbabwe) -->
+ <item>so-DJ</item> <!-- Somali (Djibouti) -->
+ <item>so-ET</item> <!-- Somali (Ethiopia) -->
+ <item>so-KE</item> <!-- Somali (Kenya) -->
+ <item>so-SO</item> <!-- Somali (Somalia) -->
+ <item>sq-AL</item> <!-- Albanian (Albania) -->
+ <item>sq-MK</item> <!-- Albanian (Macedonia (FYROM)) -->
+ <item>sq-XK</item> <!-- Albanian (Kosovo) -->
+ <item>sr-Cyrl-BA</item> <!-- Serbian (Cyrillic,Bosnia & Herzegovina) -->
+ <item>sr-Cyrl-ME</item> <!-- Serbian (Cyrillic,Montenegro) -->
+ <item>sr-Cyrl-RS</item> <!-- Serbian (Cyrillic,Serbia) -->
+ <item>sr-Cyrl-XK</item> <!-- Serbian (Cyrillic,Kosovo) -->
+ <item>sr-Latn-BA</item> <!-- Serbian (Latin,Bosnia & Herzegovina) -->
+ <item>sr-Latn-ME</item> <!-- Serbian (Latin,Montenegro) -->
+ <item>sr-Latn-RS</item> <!-- Serbian (Latin,Serbia) -->
+ <item>sr-Latn-XK</item> <!-- Serbian (Latin,Kosovo) -->
+ <item>sv-AX</item> <!-- Swedish (Åland Islands) -->
+ <item>sv-FI</item> <!-- Swedish (Finland) -->
+ <item>sv-SE</item> <!-- Swedish (Sweden) -->
+ <item>sw-CD</item> <!-- Swahili (Congo (DRC)) -->
+ <item>sw-KE</item> <!-- Swahili (Kenya) -->
+ <item>sw-TZ</item> <!-- Swahili (Tanzania) -->
+ <item>sw-UG</item> <!-- Swahili (Uganda) -->
+ <item>ta-IN</item> <!-- Tamil (India) -->
+ <item>ta-LK</item> <!-- Tamil (Sri Lanka) -->
+ <item>ta-MY</item> <!-- Tamil (Malaysia) -->
+ <item>ta-SG</item> <!-- Tamil (Singapore) -->
+ <item>te-IN</item> <!-- Telugu (India) -->
+ <item>teo-KE</item> <!-- Teso (Kenya) -->
+ <item>teo-UG</item> <!-- Teso (Uganda) -->
+ <item>th-TH</item> <!-- Thai (Thailand) -->
+ <item>ti-ER</item> <!-- Tigrinya (Eritrea) -->
+ <item>ti-ET</item> <!-- Tigrinya (Ethiopia) -->
+ <item>to-TO</item> <!-- Tongan (Tonga) -->
+ <item>tr-CY</item> <!-- Turkish (Cyprus) -->
+ <item>tr-TR</item> <!-- Turkish (Turkey) -->
+ <item>twq-NE</item> <!-- Tasawaq (Niger) -->
+ <item>tzm-MA</item> <!-- Central Atlas Tamazight (Morocco) -->
+ <item>ug-CN</item> <!-- Uyghur (China) -->
+ <item>uk-UA</item> <!-- Ukrainian (Ukraine) -->
+ <item>ur-IN</item> <!-- Urdu (India) -->
+ <item>ur-PK</item> <!-- Urdu (Pakistan) -->
+ <item>uz-Arab-AF</item> <!-- Uzbek (Arabic,Afghanistan) -->
+ <item>uz-Cyrl-UZ</item> <!-- Uzbek (Cyrillic,Uzbekistan) -->
+ <item>uz-Latn-UZ</item> <!-- Uzbek (Latin,Uzbekistan) -->
+ <item>vi-VN</item> <!-- Vietnamese (Vietnam) -->
+ <item>vun-TZ</item> <!-- Vunjo (Tanzania) -->
+ <item>wae-CH</item> <!-- Walser (Switzerland) -->
+ <item>xog-UG</item> <!-- Soga (Uganda) -->
+ <item>yav-CM</item> <!-- Yangben (Cameroon) -->
+ <item>yo-BJ</item> <!-- Yoruba (Benin) -->
+ <item>yo-NG</item> <!-- Yoruba (Nigeria) -->
+ <item>zgh-MA</item> <!-- Standard Moroccan Tamazight (Morocco) -->
+ <item>zh-Hans-CN</item> <!-- Chinese (Simplified Han,China) -->
+ <item>zh-Hans-HK</item> <!-- Chinese (Simplified Han,Hong Kong) -->
+ <item>zh-Hans-MO</item> <!-- Chinese (Simplified Han,Macau) -->
+ <item>zh-Hans-SG</item> <!-- Chinese (Simplified Han,Singapore) -->
+ <item>zh-Hant-HK</item> <!-- Chinese (Traditional Han,Hong Kong) -->
+ <item>zh-Hant-MO</item> <!-- Chinese (Traditional Han,Macau) -->
+ <item>zh-Hant-TW</item> <!-- Chinese (Traditional Han,Taiwan) -->
+ <item>zu-ZA</item> <!-- Zulu (South Africa) -->
+ </string-array>
+
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ad36f3c..09c1717 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2686,23 +2686,7 @@
<public type="attr" name="languageTag" />
<public type="attr" name="pointerShape" />
- <public type="style" name="Theme.Material.DayNight" />
- <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
- <public type="style" name="Theme.Material.DayNight.Dialog" />
- <public type="style" name="Theme.Material.DayNight.Dialog.Alert" />
- <public type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
- <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
- <public type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
- <public type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
- <public type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
- <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
- <public type="style" name="Theme.Material.DayNight.NoActionBar" />
- <public type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
- <public type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
- <public type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
- <public type="style" name="Theme.Material.DayNight.Panel" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
- <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
<public type="id" name="accessibilityActionSetProgress" />
<public type="id" name="icon_frame" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4d967ff..be9ba62 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -487,10 +487,34 @@
<!-- Take bug report menu title [CHAR LIMIT=NONE] -->
<string name="bugreport_title">Take bug report</string>
<!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
+ <!-- TODO: remove if not used anymore -->
<string name="bugreport_message">This will collect information about your
current device state, to send as an e-mail message. It will take a little
time from starting the bug report until it is ready to be sent; please be
patient.</string>
+ <!-- Title in the bugreport dialog for the interactive workflow. [CHAR LIMIT=20] -->
+ <!-- DO NOT TRANSLATE YET: final phrasing still being discussed -->
+ <string name="bugreport_option_interactive_title">Interactive report</string>
+ <!-- Summary in the bugreport dialog for the interactive workflow. [CHAR LIMIT=NONE] -->
+ <!-- DO NOT TRANSLATE YET: final phrasing still being discussed -->
+ <string name="bugreport_option_interactive_summary">Use this under most circumstances.
+ It allows you to track progress of the report and enter more details about the problem.
+ It might omit some less-used sections that take a long time to report.</string>
+ <!-- Title in the bugreport dialog for the full workflow. [CHAR LIMIT=20] -->
+ <!-- DO NOT TRANSLATE YET: final phrasing still being discussed -->
+ <string name="bugreport_option_full_title">Full report</string>
+ <!-- Summary in the bugreport dialog for the full workflow. [CHAR LIMIT=20] -->
+ <!-- DO NOT TRANSLATE YET: final phrasing still being discussed -->
+ <string name="bugreport_option_full_summary">Use this option for minimal interference when
+ your device is unresponsive or too slow, or when you need all sections.
+ Does not take a screenshot or allow you to enter more details.</string>
+ <!-- Toast message informing user in how many seconds a bugreport screenshot will be taken -->
+ <!-- DO NOT TRANSLATE YET: final phrasing still being discussed -->
+ <plurals name="bugreport_countdown">
+ <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item>
+ <item quantity="other">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> seconds.</item>
+ </plurals>
+
<!-- Format for build summary info [CHAR LIMIT=NONE] -->
<string name="bugreport_status" translatable="false">%s (%s)</string>
@@ -537,6 +561,9 @@
<!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
<string name="notification_header_divider_symbol" translatable="false">•</string>
+ <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
+ <string name="notification_hidden_text">Contents hidden</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
@@ -999,11 +1026,6 @@
<string name="permdesc_vibrate">Allows the app to control the vibrator.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_flashlight">control flashlight</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_flashlight">Allows the app to control the flashlight.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_callPhone">directly call phone numbers</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_callPhone">Allows the app to call phone numbers
@@ -2453,6 +2475,9 @@
<!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field -->
<string name="paste">Paste</string>
+ <!-- Item on EditText context menu. This action is used to paste from the clipboard into the eidt field without formatting -->
+ <string name="paste_as_plain_text">Paste as plain text</string>
+
<!-- Item on EditText context menu. This action is used to replace the current word by other suggested words, suggested by the IME or the spell checker -->
<string name="replace">Replace\u2026</string>
@@ -2465,6 +2490,12 @@
<!-- Item on EditText context menu. Added only when the context menu is not empty, it enable selection context mode. [CHAR LIMIT=20] -->
<string name="selectTextMode">Select text</string>
+ <!-- Item on EditText context menu. This action is used to undo a text edit operation. -->
+ <string name="undo">Undo</string>
+
+ <!-- Item on EditText context menu. This action is used to redo a text edit operation. -->
+ <string name="redo">Redo</string>
+
<!-- Text selection contextual mode title, displayed in the CAB. [CHAR LIMIT=20] -->
<string name="textSelectionCABTitle">Text selection</string>
@@ -3069,6 +3100,9 @@
<string name="notification_listener_binding_label">Notification listener</string>
<!-- Label to show for a service that is running because it is providing conditions. -->
<string name="condition_provider_service_binding_label">Condition provider</string>
+ <!-- Label to show for a service that is running because it is observing and modifying the
+ importance of the user's notifications. -->
+ <string name="notification_assistant_binding_label">Notification assistant</string>
<!-- Do Not Translate: Alternate eri.xml -->
<string name="alternate_eri_file">/data/eri.xml</string>
@@ -3954,25 +3988,6 @@
<!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
<string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
-
- <!-- [CHAR LIMIT=100] Notification importance slider title -->
- <string name="notification_importance_title">Importance</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
- <string name="notification_importance_blocked">Blocked: Never show these notifications</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
- <string name="notification_importance_low">Low: Silently show at the bottom of the notification list</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
- <string name="notification_importance_default">Normal: Silently show these notifications</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
- <string name="notification_importance_high">High: Show at the top of the notifications list and make sound</string>
-
- <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
- <string name="notification_importance_max">Urgent: Peek onto the screen and make sound</string>
-
<!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
<plurals name="zen_mode_duration_minutes_summary">
<item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 9a4016b..937d83d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1235,7 +1235,7 @@
<item name="subtitleTextAppearance">@style/TextAppearance.Widget.Toolbar.Subtitle</item>
<item name="minHeight">?attr/actionBarSize</item>
<item name="titleMargin">4dp</item>
- <item name="maxButtonHeight">56dp</item>
+ <item name="maxButtonHeight">@dimen/action_bar_default_height_material</item>
<item name="buttonGravity">top</item>
<item name="navigationButtonStyle">@style/Widget.Toolbar.Button.Navigation</item>
<item name="collapseIcon">?attr/homeAsUpIndicator</item>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 74ebf26..8485e59 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -432,6 +432,8 @@
<item name="textSize">@dimen/notification_text_size</item>
</style>
+ <style name="TextAppearance.Material.Notification.Reply" />
+
<style name="TextAppearance.Material.Notification.Title">
<item name="textColor">@color/primary_text_default_material_light</item>
<item name="textSize">@dimen/notification_title_text_size</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 05835e7..7dde5f8 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -26,6 +26,10 @@
<item name="taskOpenExitAnimation">@null</item>
<item name="taskCloseEnterAnimation">@null</item>
<item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
+ <item name="taskToFrontEnterAnimation">@anim/slide_in_micro</item>
+ <item name="taskToFrontExitAnimation">@null</item>
+ <item name="taskToBackEnterAnimation">@null</item>
+ <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperOpenEnterAnimation">@null</item>
<item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
<item name="wallpaperCloseEnterAnimation">@anim/slide_in_micro</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 36ba306..845c8c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -303,6 +303,7 @@
<java-symbol type="bool" name="config_supportMicNearUltrasound" />
<java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
<java-symbol type="bool" name="config_freeformWindowManagement" />
+ <java-symbol type="string" name="config_defaultPictureInPictureBounds" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_factor" />
<java-symbol type="integer" name="config_wifi_framework_5GHz_preference_penalty_threshold" />
@@ -455,7 +456,10 @@
<java-symbol type="string" name="notification_title" />
<java-symbol type="string" name="permission_request_notification_with_subtitle" />
<java-symbol type="string" name="prepend_shortcut_label" />
+ <java-symbol type="string" name="paste_as_plain_text" />
<java-symbol type="string" name="replace" />
+ <java-symbol type="string" name="undo" />
+ <java-symbol type="string" name="redo" />
<java-symbol type="string" name="textSelectionCABTitle" />
<java-symbol type="string" name="BaMmi" />
<java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
@@ -1100,6 +1104,7 @@
<java-symbol type="string" name="config_ethernet_tcp_buffers" />
<java-symbol type="string" name="config_wifi_tcp_buffers" />
+ <java-symbol type="plurals" name="bugreport_countdown" />
<java-symbol type="plurals" name="duration_hours" />
<java-symbol type="plurals" name="duration_minutes" />
<java-symbol type="plurals" name="duration_seconds" />
@@ -1120,6 +1125,7 @@
<java-symbol type="array" name="sim_colors" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
+ <java-symbol type="array" name="supported_locales" />
<java-symbol type="array" name="config_cdma_dun_supported_types" />
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
<java-symbol type="array" name="config_disabledUntilUsedPreinstalledCarrierApps" />
@@ -1243,6 +1249,7 @@
<java-symbol type="drawable" name="cling_arrow_up" />
<java-symbol type="drawable" name="cling_bg" />
<java-symbol type="drawable" name="ic_corp_badge" />
+ <java-symbol type="drawable" name="ic_corp_badge_off" />
<java-symbol type="drawable" name="ic_corp_icon_badge" />
<java-symbol type="drawable" name="ic_corp_icon" />
<java-symbol type="drawable" name="ic_corp_statusbar_icon" />
@@ -1485,6 +1492,8 @@
<java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
<java-symbol type="dimen" name="docked_stack_divider_thickness" />
<java-symbol type="dimen" name="docked_stack_divider_insets" />
+ <java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
+ <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
<java-symbol type="dimen" name="navigation_bar_height" />
<java-symbol type="dimen" name="navigation_bar_height_landscape" />
<java-symbol type="dimen" name="navigation_bar_width" />
@@ -1558,9 +1567,13 @@
<java-symbol type="string" name="android_preparing_apk" />
<java-symbol type="string" name="android_start_title" />
<java-symbol type="string" name="android_upgrading_title" />
- <java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="bugreport_message" />
+ <java-symbol type="string" name="bugreport_option_full_summary" />
+ <java-symbol type="string" name="bugreport_option_full_title" />
+ <java-symbol type="string" name="bugreport_option_interactive_summary" />
+ <java-symbol type="string" name="bugreport_option_interactive_title" />
<java-symbol type="string" name="bugreport_status" />
+ <java-symbol type="string" name="bugreport_title" />
<java-symbol type="string" name="config_orientationSensorType" />
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_action_power_off" />
@@ -1805,6 +1818,7 @@
<java-symbol type="string" name="low_internal_storage_view_title" />
<java-symbol type="string" name="notification_listener_binding_label" />
<java-symbol type="string" name="condition_provider_service_binding_label" />
+ <java-symbol type="string" name="notification_assistant_binding_label" />
<java-symbol type="string" name="report" />
<java-symbol type="string" name="select_input_method" />
<java-symbol type="string" name="select_keyboard_layout_notification_title" />
@@ -2085,12 +2099,6 @@
<java-symbol type="array" name="config_system_condition_providers" />
<java-symbol type="string" name="muted_by" />
<java-symbol type="string" name="zen_mode_alarm" />
- <java-symbol type="string" name="notification_importance_blocked" />
- <java-symbol type="string" name="notification_importance_low" />
- <java-symbol type="string" name="notification_importance_default" />
- <java-symbol type="string" name="notification_importance_high" />
- <java-symbol type="string" name="notification_importance_max" />
- <java-symbol type="string" name="notification_importance_title" />
<java-symbol type="string" name="select_day" />
<java-symbol type="string" name="select_year" />
@@ -2360,7 +2368,13 @@
<java-symbol type="id" name="addToDictionaryButton" />
<java-symbol type="id" name="deleteButton" />
+ <java-symbol type="id" name="notification_material_reply_container" />
+ <java-symbol type="id" name="notification_material_reply_text_1" />
+ <java-symbol type="id" name="notification_material_reply_text_2" />
+ <java-symbol type="id" name="notification_material_reply_text_3" />
+
<java-symbol type="string" name="notification_children_count_bracketed" />
+ <java-symbol type="string" name="notification_hidden_text" />
<java-symbol type="id" name="app_name_text" />
<java-symbol type="id" name="number_of_children" />
<java-symbol type="id" name="header_sub_text" />
@@ -2376,7 +2390,7 @@
<java-symbol type="drawable" name="ic_expand_bundle" />
<java-symbol type="drawable" name="ic_collapse_bundle" />
<java-symbol type="dimen" name="notification_header_height" />
- <java-symbol type="dimen" name="notification_big_picture_content_min_height_with_picture" />
+ <java-symbol type="dimen" name="notification_min_content_height" />
<java-symbol type="dimen" name="notification_header_shrink_min_width" />
<java-symbol type="dimen" name="notification_content_margin_start" />
<java-symbol type="dimen" name="notification_content_margin_end" />
@@ -2384,4 +2398,26 @@
<java-symbol type="dimen" name="notification_content_margin_top" />
<java-symbol type="string" name="importance_from_topic" />
<java-symbol type="string" name="importance_from_person" />
+
+ <java-symbol type="layout" name="work_widget_mask_view" />
+ <java-symbol type="id" name="work_widget_app_icon" />
+ <java-symbol type="drawable" name="work_widget_mask_view_background" />
+
+ <!-- Framework-private Material.DayNight styles. -->
+ <java-symbol type="style" name="Theme.Material.DayNight" />
+ <java-symbol type="style" name="Theme.Material.DayNight.DarkActionBar" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Alert" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog.MinWidth" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog.NoActionBar.MinWidth" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Dialog.Presentation" />
+ <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge" />
+ <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.NoActionBar" />
+ <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar" />
+ <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Fullscreen" />
+ <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.Overscan" />
+ <java-symbol type="style" name="Theme.Material.DayNight.NoActionBar.TranslucentDecor" />
+ <java-symbol type="style" name="Theme.Material.DayNight.Panel" />
+ <java-symbol type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
</resources>
diff --git a/core/res/res/xml/config_webview_packages.xml b/core/res/res/xml/config_webview_packages.xml
index 6f9c58d..fd443c1 100644
--- a/core/res/res/xml/config_webview_packages.xml
+++ b/core/res/res/xml/config_webview_packages.xml
@@ -16,5 +16,6 @@
<webviewproviders>
<!-- The default WebView implementation -->
- <webviewprovider description="Android WebView" packageName="com.android.webview" />
+ <webviewprovider description="Android WebView" packageName="com.android.webview">
+ </webviewprovider>
</webviewproviders>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 7cd25af..ee8921e 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,7 +22,7 @@
$(call all-java-files-under, EnabledTestApp/src)
LOCAL_DX_FLAGS := --core-library
-LOCAL_AAPT_FLAGS = -0 dat -0 gld
+LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
LOCAL_STATIC_JAVA_LIBRARIES := \
core-tests-support \
android-common \
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 5177836..c0453f8 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -146,6 +146,16 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.DatePickerActivity"
+ android:label="DatePickerActivity"
+ android:screenOrientation="portrait"
+ android:theme="@android:style/Theme.Material.Light">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/datepicker_layout.xml b/core/tests/coretests/res/layout/datepicker_layout.xml
new file mode 100644
index 0000000..a79f87d
--- /dev/null
+++ b/core/tests/coretests/res/layout/datepicker_layout.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <DatePicker
+ android:id="@+id/datePicker"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerInParent="true"/>
+ <EditText
+ android:id="@+id/belowPicker"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Some Text"
+ android:textAlignment="center"
+ android:layout_below="@id/datePicker"/>
+</RelativeLayout>
diff --git a/core/tests/coretests/res/values-fa/strings.xml b/core/tests/coretests/res/values-fa/strings.xml
new file mode 100644
index 0000000..c83f5f1
--- /dev/null
+++ b/core/tests/coretests/res/values-fa/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="dummy_string">رشتهٔ الکی</string>
+</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 04b0478..ef915bb 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -139,4 +139,7 @@
<!-- RestrictionsManagerTest -->
<string name="restrictionManager_title">Title</string>
<string name="restrictionManager_desc">Description</string>
+
+ <!-- ResourcesLocaleResolutionTest -->
+ <string name="dummy_string">dummy string</string>
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
index dcf2c89..9c03e1a 100644
--- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -90,6 +90,18 @@
assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);
}
+ public void testQueryAppsRequiredForSystemUser() {
+ // Test query only system apps required for system user
+ List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER,
+ true, UserHandle.SYSTEM);
+ assertEqualsIgnoreOrder(Arrays.asList("sys_app3"), apps);
+
+ // Test query all apps required for system user
+ apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER, false,
+ UserHandle.SYSTEM);
+ assertEqualsIgnoreOrder(Arrays.asList("sys_app3", "app4"), apps);
+ }
+
private class AppsQueryHelperTestable extends AppsQueryHelper {
@Override
@@ -104,7 +116,9 @@
final ApplicationInfo ai3 = new ApplicationInfo();
ai3.packageName = "sys_app3";
ai3.flags |= ApplicationInfo.FLAG_SYSTEM;
+ ai3.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
final ApplicationInfo ai4 = new ApplicationInfo();
+ ai4.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
ai4.packageName = "app4";
return Arrays.asList(ai1, ai2, ai3, ai4);
}
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
deleted file mode 100644
index 37495e1..0000000
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ /dev/null
@@ -1,77 +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 android.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-
-public class ManifestDigestTest extends AndroidTestCase {
- private static final byte[] MESSAGE_1 = {
- (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
- };
-
- public void testManifestDigest_FromInputStream_Null() {
- assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
- ManifestDigest.fromInputStream(null));
- }
-
- public void testManifestDigest_FromInputStream_ThrowsIoException() {
- InputStream is = new InputStream() {
- @Override
- public int read() throws IOException {
- throw new IOException();
- }
- };
-
- assertNull("InputStream threw exception, so ManifestDigest should be null",
- ManifestDigest.fromInputStream(is));
- }
-
- public void testManifestDigest_Equals() throws Exception {
- InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
- ManifestDigest expected =
- new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));
-
- ManifestDigest actual = ManifestDigest.fromInputStream(is);
- assertEquals(expected, actual);
-
- ManifestDigest unexpected = new ManifestDigest(new byte[0]);
- assertFalse(unexpected.equals(actual));
- }
-
- public void testManifestDigest_Parcel() throws Exception {
- InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
- ManifestDigest digest = ManifestDigest.fromInputStream(is);
-
- Parcel p = Parcel.obtain();
- digest.writeToParcel(p, 0);
- p.setDataPosition(0);
-
- ManifestDigest fromParcel = ManifestDigest.CREATOR.createFromParcel(p);
-
- assertEquals("ManifestDigest going through parceling should be the same as before: "
- + digest.toString() + " and " + fromParcel.toString(), digest,
- fromParcel);
- }
-}
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 9b216cb..d963812 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.pm.ManifestDigest;
import android.content.pm.VerificationParams;
import android.net.Uri;
import android.os.Parcel;
@@ -33,7 +32,6 @@
private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
private final static String REFERRER_STRING = "http://referrer.uri/path";
- private final static byte[] DIGEST_BYTES = "fake digest".getBytes();
private final static int INSTALLER_UID = 42;
private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
@@ -42,11 +40,9 @@
private final static int ORIGINATING_UID = 10042;
- private final static ManifestDigest MANIFEST_DIGEST = new ManifestDigest(DIGEST_BYTES);
-
public void testParcel() throws Exception {
VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
Parcel parcel = Parcel.obtain();
expected.writeToParcel(parcel, 0);
@@ -61,85 +57,70 @@
assertEquals(REFERRER, actual.getReferrer());
assertEquals(ORIGINATING_UID, actual.getOriginatingUid());
-
- assertEquals(MANIFEST_DIGEST, actual.getManifestDigest());
}
public void testEquals_Success() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertEquals(params1, params2);
}
public void testEquals_VerificationUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_OriginatingUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_Referrer_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse("http://a.different.uri/"), ORIGINATING_UID,
- new ManifestDigest(DIGEST_BYTES));
+ Uri.parse("http://a.different.uri/"), ORIGINATING_UID);
assertFalse(params1.equals(params2));
}
public void testEquals_Originating_Uid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
- assertFalse(params1.equals(params2));
- }
-
- public void testEquals_ManifestDigest_Failure() throws Exception {
- VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
- VerificationParams params2 = new VerificationParams(
- Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), 12345);
assertFalse(params1.equals(params2));
}
public void testEquals_InstallerUid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
params2.setInstallerUid(INSTALLER_UID);
assertFalse(params1.equals(params2));
@@ -147,78 +128,65 @@
public void testHashCode_Success() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertEquals(params1.hashCode(), params2.hashCode());
}
public void testHashCode_VerificationUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_OriginatingUri_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_Referrer_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
- ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+ ORIGINATING_UID);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_Originating_Uid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
- assertFalse(params1.hashCode() == params2.hashCode());
- }
-
- public void testHashCode_ManifestDigest_Failure() throws Exception {
- VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
- VerificationParams params2 = new VerificationParams(
- Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), 12345);
assertFalse(params1.hashCode() == params2.hashCode());
}
public void testHashCode_InstallerUid_Failure() throws Exception {
VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
- REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+ REFERRER, ORIGINATING_UID);
VerificationParams params2 = new VerificationParams(
Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
- Uri.parse(REFERRER_STRING), ORIGINATING_UID,
- new ManifestDigest("a different digest".getBytes()));
+ Uri.parse(REFERRER_STRING), ORIGINATING_UID);
params2.setInstallerUid(INSTALLER_UID);
assertFalse(params1.hashCode() == params2.hashCode());
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
new file mode 100644
index 0000000..55c0031
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT 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.res;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public class ResourcesLocaleResolutionTest extends AndroidTestCase {
+ @SmallTest
+ public void testGetResolvedLocale_englishIsAlwaysConsideredSupported() {
+ // First make sure English has no explicit assets other than the default assets
+ final AssetManager assets = getContext().getAssets();
+ final String supportedLocales[] = assets.getNonSystemLocales();
+ for (String languageTag : supportedLocales) {
+ if ("en-XA".equals(languageTag)) {
+ continue;
+ }
+ assertFalse(
+ "supported locales: " + Arrays.toString(supportedLocales),
+ "en".equals(Locale.forLanguageTag(languageTag).getLanguage()));
+ }
+
+ final DisplayMetrics dm = new DisplayMetrics();
+ dm.setToDefaults();
+ final Configuration cfg = new Configuration();
+ cfg.setToDefaults();
+ // Avestan and English have no assets, but Persian does.
+ cfg.setLocales(LocaleList.forLanguageTags("ae,en,fa"));
+ Resources res = new Resources(assets, dm, cfg);
+ // We should get English, because it is always considered supported.
+ assertEquals("en", res.getResolvedLocale().toLanguageTag());
+ }
+}
+
diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java
index 253eb25..d383775 100644
--- a/core/tests/coretests/src/android/util/PatternsTest.java
+++ b/core/tests/coretests/src/android/util/PatternsTest.java
@@ -17,14 +17,16 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.Suppress;
-import android.util.Patterns;
import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import junit.framework.TestCase;
public class PatternsTest extends TestCase {
+ //Tests for Patterns.TOP_LEVEL_DOMAIN
+
@SmallTest
public void testTldPattern() throws Exception {
boolean t;
@@ -40,7 +42,7 @@
t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches();
assertTrue("Missed valid TLD", t);
- // One of the new top level internationalized domain.
+ // One of the new top level unicode domain.
t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches();
assertTrue("Missed valid TLD", t);
@@ -54,60 +56,372 @@
assertFalse("Matched invalid TLD!", t);
}
+ //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+
@SmallTest
- @Suppress // Failing.
- public void testUrlPattern() throws Exception {
- boolean t;
-
- t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
- assertTrue("Valid URL", t);
-
- // Google in one of the new top level domain.
- t = Patterns.WEB_URL.matcher("http://www.google.me").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("google.me").matches();
- assertTrue("Valid URL", t);
-
- // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d
- t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
- assertTrue("Valid URL", t);
-
- // Url for testing top level Arabic country code domain in Punycode:
- // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx
- t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches();
- assertTrue("Valid URL", t);
-
- // Internationalized URL.
- t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid URL", t);
- t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid URL", t);
- // URL with international TLD.
- t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches();
- assertTrue("Valid URL", t);
-
- t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
- "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches();
- assertTrue("Valid URL", t);
-
- t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
- assertFalse("Matched invalid protocol", t);
-
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches();
- assertTrue("Didn't match valid URL with port", t);
-
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches();
- assertTrue("Didn't match valid URL with port and query args", t);
-
- t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
- assertTrue("Didn't match valid URL with ~", t);
+ public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match 'com'", pattern.matcher("com").matches());
}
@SmallTest
+ public void testIanaTopLevelDomains_matchesValidNewTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match 'me'", pattern.matcher("me").matches());
+ }
+
+ @SmallTest
+ public void testIanaTopLevelDomains_matchesPunycodeTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match Punycode TLD", pattern.matcher("xn--qxam").matches());
+ }
+
+ @SmallTest
+ public void testIanaTopLevelDomains_matchesIriTLD() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertTrue("Should match IRI TLD", pattern.matcher("\uD55C\uAD6D").matches());
+ }
+
+ @SmallTest
+ public void testIanaTopLevelDomains_doesNotMatchWrongTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertFalse("Should not match 'mem'", pattern.matcher("mem").matches());
+ }
+
+ @SmallTest
+ public void testIanaTopLevelDomains_doesNotMatchWrongPunycodeTld() throws Exception {
+ Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS);
+ assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
+ }
+
+ //Tests for Patterns.WEB_URL
+
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+ String url = "http://www.android.com";
+ assertTrue("Should match URL with scheme and hostname",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+ String url = "http://www.android.me";
+ assertTrue("Should match URL with scheme, hostname and new TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+ String url = "android.me";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL with protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL without protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+
+ @SmallTest
+ public void testWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match arabic Punycode URL with protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL without protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeDomainNameWithProtocol() throws Exception {
+ String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL with Unicode domain name",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception {
+ String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL without protocol and with Unicode domain name",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+ String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+ assertTrue("Should match URL with Unicode TLD",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithUnicodePath() throws Exception {
+ String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+ "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+ assertTrue("Should match URL with Unicode path",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+ String url = "ftp://www.example.com";
+ assertFalse("Should not match URL with invalid protocol",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesValidUrlWithPort() throws Exception {
+ String url = "http://www.example.com:8080";
+ assertTrue("Should match URL with port", Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+ String url = "http://www.example.com:8080/?foo=bar";
+ assertTrue("Should match URL with port and query",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesUrlWithTilde() throws Exception {
+ String url = "http://www.example.com:8080/~user/?foo=bar";
+ assertTrue("Should match URL with tilde", Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+ String url = "hTtP://android.com";
+ assertTrue("Protocol matching should be case insensitive",
+ Patterns.WEB_URL.matcher(url).matches());
+ }
+
+ //Tests for Patterns.AUTOLINK_WEB_URL
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
+ String url = "http://www.android.com";
+ assertTrue("Should match URL with scheme and hostname",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception {
+ String url = "http://www.android.me";
+ assertTrue("Should match URL with scheme, hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception {
+ String url = "android.me";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+ url = "android.camera";
+ assertTrue("Should match URL with hostname and new TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL with protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match Chinese Punycode URL without protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception {
+ String url = "http://xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL with protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception {
+ String url = "xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx";
+ assertTrue("Should match Arabic Punycode URL without protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception {
+ String url = "http://xn--fsqu00a.-xn--0zwm56d";
+ assertFalse("Should not match Punycode TLD that starts with dash",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatEndsWithDash() throws Exception {
+ String url = "http://xn--fsqu00a.xn--0zwm56d-";
+ assertFalse("Should not match Punycode TLD that ends with dash",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodeDomainName() throws Exception {
+ String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match URL with Unicode domain name",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+
+ url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("hould match URL without protocol and with Unicode domain name",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodeTld() throws Exception {
+ String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+ assertTrue("Should match URL with Unicode TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithUnicodePath() throws Exception {
+ String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" +
+ "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/";
+ assertTrue("Should match URL with Unicode path",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception {
+ String url = "ftp://www.example.com";
+ assertFalse("Should not match URL with invalid protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithPort() throws Exception {
+ String url = "http://www.example.com:8080";
+ assertTrue("Should match URL with port",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithPortAndQuery() throws Exception {
+ String url = "http://www.example.com:8080/?foo=bar";
+ assertTrue("Should match URL with port and query",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlWithTilde() throws Exception {
+ String url = "http://www.example.com:8080/~user/?foo=bar";
+ assertTrue("Should match URL with tilde",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesProtocolCaseInsensitive() throws Exception {
+ String url = "hTtP://android.com";
+ assertTrue("Protocol matching should be case insensitive",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception {
+ String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
+ assertTrue("Should match URL without a TLD and starting with http ",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld()
+ throws Exception {
+ String url = "thank.you";
+ assertFalse("Should not match URL that does not start with a protocol and " +
+ "does not contain a known TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlWithInvalidRequestParameter() throws Exception {
+ String url = "http://android.com?p=value";
+ assertFalse("Should not match URL with invalid request parameter",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotPartiallyMatchUnknownProtocol() throws Exception {
+ String url = "ftp://foo.bar/baz";
+ assertFalse("Should not partially match URL with unknown protocol",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).find());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesValidUrlWithEmoji() throws Exception {
+ String url = "Thank\u263A.com";
+ assertTrue("Should match URL with emoji",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld()
+ throws Exception {
+ String url = "Thank\u263A.you";
+ assertFalse("Should not match URLs containing emoji and with unknown TLD",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchEmailAddress()
+ throws Exception {
+ String url = "android@android.com";
+ assertFalse("Should not match email address",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesDomainNameWithSurrogatePairs() throws Exception {
+ String url = "android\uD83C\uDF38.com";
+ assertTrue("Should match domain name with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesTldWithSurrogatePairs() throws Exception {
+ String url = "http://android.\uD83C\uDF38com";
+ assertTrue("Should match TLD with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_matchesPathWithSurrogatePairs() throws Exception {
+ String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38";
+ assertTrue("Should match path and query with Unicode surrogate pairs",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ @SmallTest
+ public void testAutoLinkWebUrl_doesNotMatchUrlWithExcludedSurrogate() throws Exception {
+ String url = "http://android\uD83F\uDFFE.com";
+ assertFalse("Should not match URL with excluded Unicode surrogate pair",
+ Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
+ }
+
+ //Tests for Patterns.IP_ADDRESS
+
+ @SmallTest
public void testIpPattern() throws Exception {
boolean t;
@@ -118,34 +432,85 @@
assertFalse("Invalid IP", t);
}
+ //Tests for Patterns.DOMAIN_NAME
+
@SmallTest
- @Suppress // Failing.
- public void testDomainPattern() throws Exception {
- boolean t;
-
- t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches();
- assertTrue("Valid domain", t);
-
- t = Patterns.DOMAIN_NAME.matcher("google.me").matches();
- assertTrue("Valid domain", t);
-
- // Internationalized domains.
- t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches();
- assertTrue("Valid domain", t);
-
- t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches();
- assertFalse("Invalid domain", t);
-
- // Obsolete domain .yu
- t = Patterns.DOMAIN_NAME.matcher("test.yu").matches();
- assertFalse("Obsolete country code top level domain", t);
-
- // Testing top level Arabic country code domain in Punycode:
- t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches();
- assertTrue("Valid domain", t);
+ public void testDomain_matchesPunycodeTld() throws Exception {
+ String domain = "xn--fsqu00a.xn--0zwm56d";
+ assertTrue("Should match domain name in Punycode",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
}
@SmallTest
+ public void testDomain_doesNotMatchPunycodeThatStartsWithDash() throws Exception {
+ String domain = "xn--fsqu00a.-xn--0zwm56d";
+ assertFalse("Should not match Punycode TLD that starts with a dash",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_doesNotMatchPunycodeThatEndsWithDash() throws Exception {
+ String domain = "xn--fsqu00a.xn--0zwm56d-";
+ assertFalse("Should not match Punycode TLD that ends with a dash",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_doesNotMatchPunycodeLongerThanAllowed() throws Exception {
+ String tld = "xn--";
+ for(int i=0; i<=6; i++) {
+ tld += "0123456789";
+ }
+ String domain = "xn--fsqu00a." + tld;
+ assertFalse("Should not match Punycode TLD that is longer than 63 chars",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesObsoleteTld() throws Exception {
+ String domain = "test.yu";
+ assertTrue("Should match domain names with obsolete TLD",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesWithSubDomain() throws Exception {
+ String domain = "mail.example.com";
+ assertTrue("Should match domain names with subdomains",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesWithoutSubDomain() throws Exception {
+ String domain = "android.me";
+ assertTrue("Should match domain names without subdomains",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesUnicodeDomainNames() throws Exception {
+ String domain = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+ assertTrue("Should match unicodedomain names",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_doesNotMatchInvalidDomain() throws Exception {
+ String domain = "__+&42.xer";
+ assertFalse("Should not match invalid domain name",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ @SmallTest
+ public void testDomain_matchesPunycodeArabicDomainName() throws Exception {
+ String domain = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c";
+ assertTrue("Should match Punycode Arabic domain name",
+ Patterns.DOMAIN_NAME.matcher(domain).matches());
+ }
+
+ //Tests for Patterns.PHONE
+
+ @SmallTest
public void testPhonePattern() throws Exception {
boolean t;
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
new file mode 100644
index 0000000..c3b25a1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+/**
+ * A minimal application for DatePickerFocusTest.
+ */
+public class DatePickerActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.datepicker_layout);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
new file mode 100644
index 0000000..513e40f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.widget;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * Test {@link DatePicker} focus changes.
+ */
+public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
+
+ private Activity mActivity;
+ private Instrumentation mInstrumentation;
+ private DatePicker mDatePicker;
+
+ public DatePickerFocusTest() {
+ super(DatePickerActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInstrumentation = getInstrumentation();
+
+ mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
+ }
+
+ /**
+ * Tabs (forward and backward) through the DatePicker to ensure the correct
+ * Views gain focus.
+ */
+ public void testFocusTravel() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertTrue(mDatePicker.requestFocus());
+ }
+ });
+ assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.next);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(R.id.belowPicker);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.next);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ sendShiftKey(KeyEvent.KEYCODE_TAB);
+ assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+ }
+
+ private void sendKey(int keycode) {
+ mInstrumentation.sendKeyDownUpSync(keycode);
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private void assertViewHasFocus(final int id) throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View view = mActivity.findViewById(id);
+ assertTrue(view.hasFocus());
+ }
+ });
+ }
+
+ private void sendShiftKey(int keycode) {
+ final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
+ mInstrumentation.sendKeySync(shiftDown);
+
+ final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
+ KeyEvent.META_SHIFT_ON);
+ mInstrumentation.sendKeySync(keyDown);
+
+ final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
+ SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
+ KeyEvent.META_SHIFT_ON);
+ mInstrumentation.sendKeySync(keyUp);
+
+ final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
+ mInstrumentation.sendKeySync(shiftUp);
+
+ mInstrumentation.waitForIdleSync();
+ }
+
+ /**
+ * Tests to ensure the keyboard can select the current year.
+ */
+ public void testYearChoice() throws Throwable {
+ setKnownDate();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View year = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_header_year);
+ assertTrue(year.requestFocus());
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View yearSelect = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_year_picker);
+ assertEquals(yearSelect, mDatePicker.findFocus());
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View yearSelect = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_year_picker);
+ assertNotSame(View.VISIBLE, yearSelect.getVisibility());
+ View year = mDatePicker.
+ findViewById(com.android.internal.R.id.date_picker_header_year);
+ assertTrue(year.hasFocus());
+ assertEquals(2014, mDatePicker.getYear());
+ }
+ });
+ }
+
+ public void testArrowThroughDays() throws Throwable {
+ setKnownDate();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
+ prev.requestFocus();
+ }
+ });
+ sendKey(KeyEvent.KEYCODE_TAB);
+ // Should select the current date and the date shouldn't change
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 31, 2015);
+ // Move right to January 24, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 24, 2016);
+ // Move down to January 31, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 31, 2016);
+ // Move up to January 5, 2016
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 5, 2016);
+ // Move up to prev arrow key
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ assertViewHasFocus(com.android.internal.R.id.prev);
+ // tab back into the day-selection pager
+ sendKey(KeyEvent.KEYCODE_TAB);
+ sendKey(KeyEvent.KEYCODE_TAB);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ assertDateIs(1, 5, 2016);
+
+ // Move up out again, then down back into the day-selection pager.
+ // It should land right below the prev button (1/3/2016)
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+ assertDateIs(1, 3, 2016);
+
+ // Move left to previous month (12/12/2015)
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 12, 2015);
+ // Now make sure the start of the month works
+ // Move up to 12/5/2015 and right to 1/1/2016
+ sendKey(KeyEvent.KEYCODE_DPAD_UP);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(1, 1, 2016);
+ // Now make sure the left key goes back to previous month (12/5/2015)
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 5, 2015);
+ // Now go to a mismatched row (no such row on previous month)
+ // This moves over to 1/31/2016 and then left to 12/31/2015
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+ sendKey(KeyEvent.KEYCODE_ENTER);
+ assertDateIs(12, 31, 2015);
+ }
+
+ private void assertDateIs(int month, final int day, final int year) throws Throwable {
+ final int monthInt = month - 1; // months are 0-based
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ assertEquals(day, mDatePicker.getDayOfMonth());
+ assertEquals(year, mDatePicker.getYear());
+ assertEquals(monthInt, mDatePicker.getMonth());
+ }
+ });
+ }
+
+ private void setKnownDate() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
index 83a9e01..afd0bc4 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -26,8 +26,11 @@
import static android.widget.espresso.TextViewActions.mouseLongClickAndDragOnText;
import static android.widget.espresso.TextViewActions.mouseTripleClickAndDragOnText;
import static android.widget.espresso.TextViewActions.mouseTripleClickOnTextAtIndex;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
import static android.widget.espresso.TextViewAssertions.hasSelection;
+
import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
@@ -37,8 +40,11 @@
import com.android.frameworks.coretests.R;
+import android.support.test.espresso.Espresso;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
+import android.view.MotionEvent;
+import android.widget.espresso.ContextMenuUtils;
/**
* Tests mouse interaction of the TextView widget from an Activity
@@ -49,10 +55,13 @@
super(TextViewActivity.class);
}
+ @Override
+ public void setUp() {
+ getActivity();
+ }
+
@SmallTest
public void testSelectTextByDrag() throws Exception {
- getActivity();
-
final String helloWorld = "Hello world!";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -77,8 +86,6 @@
@SmallTest
public void testSelectTextByDrag_reverse() throws Exception {
- getActivity();
-
final String helloWorld = "Hello world!";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -89,9 +96,56 @@
}
@SmallTest
- public void testSelectTextByLongClick() throws Exception {
- getActivity();
+ public void testContextMenu() throws Exception {
+ final String text = "abc def ghi.";
+ onView(withId(R.id.textview)).perform(click());
+ onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+ ContextMenuUtils.assertContextMenuIsNotDisplayed();
+
+ onView(withId(R.id.textview)).perform(
+ mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));
+
+ ContextMenuUtils.assertContextMenuContainsItemDisabled(
+ getActivity().getString(com.android.internal.R.string.copy));
+ ContextMenuUtils.assertContextMenuContainsItemEnabled(
+ getActivity().getString(com.android.internal.R.string.undo));
+
+ // Hide context menu.
+ pressBack();
+ ContextMenuUtils.assertContextMenuIsNotDisplayed();
+
+ onView(withId(R.id.textview)).perform(
+ mouseDragOnText(text.indexOf("c"), text.indexOf("h")));
+ onView(withId(R.id.textview)).perform(
+ mouseClickOnTextAtIndex(text.indexOf("d"), MotionEvent.BUTTON_SECONDARY));
+
+ ContextMenuUtils.assertContextMenuContainsItemEnabled(
+ getActivity().getString(com.android.internal.R.string.copy));
+ ContextMenuUtils.assertContextMenuContainsItemEnabled(
+ getActivity().getString(com.android.internal.R.string.undo));
+
+ // Hide context menu.
+ pressBack();
+
+ onView(withId(R.id.textview)).check(hasSelection("c def g"));
+
+ onView(withId(R.id.textview)).perform(
+ mouseClickOnTextAtIndex(text.indexOf("i"), MotionEvent.BUTTON_SECONDARY));
+ ContextMenuUtils.assertContextMenuContainsItemDisabled(
+ getActivity().getString(com.android.internal.R.string.copy));
+ ContextMenuUtils.assertContextMenuContainsItemEnabled(
+ getActivity().getString(com.android.internal.R.string.undo));
+
+ // Hide context menu.
+ pressBack();
+
+ onView(withId(R.id.textview)).check(hasSelection(""));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
+ }
+
+ @SmallTest
+ public void testSelectTextByLongClick() throws Exception {
final String helloWorld = "Hello world!";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -117,8 +171,6 @@
@SmallTest
public void testSelectTextByDoubleClick() throws Exception {
- getActivity();
-
final String helloWorld = "Hello world!";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
@@ -144,8 +196,6 @@
@SmallTest
public void testSelectTextByDoubleClickAndDrag() throws Exception {
- getActivity();
-
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -157,8 +207,6 @@
@SmallTest
public void testSelectTextByDoubleClickAndDrag_reverse() throws Exception {
- getActivity();
-
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -170,8 +218,6 @@
@SmallTest
public void testSelectTextByLongPressAndDrag() throws Exception {
- getActivity();
-
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -183,8 +229,6 @@
@SmallTest
public void testSelectTextByLongPressAndDrag_reverse() throws Exception {
- getActivity();
-
final String text = "abcd efg hijk lmn";
onView(withId(R.id.textview)).perform(click());
onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
@@ -196,8 +240,6 @@
@SmallTest
public void testSelectTextByTripleClick() throws Exception {
- getActivity();
-
final StringBuilder builder = new StringBuilder();
builder.append("First paragraph.\n");
builder.append("Second paragraph.");
@@ -232,8 +274,6 @@
@SmallTest
public void testSelectTextByTripleClickAndDrag() throws Exception {
- getActivity();
-
final StringBuilder builder = new StringBuilder();
builder.append("First paragraph.\n");
builder.append("Second paragraph.");
@@ -263,8 +303,6 @@
@SmallTest
public void testSelectTextByTripleClickAndDrag_reverse() throws Exception {
- getActivity();
-
final StringBuilder builder = new StringBuilder();
builder.append("First paragraph.\n");
builder.append("Second paragraph.");
diff --git a/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
new file mode 100644
index 0000000..c8218aa
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/ContextMenuUtils.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.widget.espresso;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.not;
+
+import com.android.internal.view.menu.ListMenuItemView;
+
+import android.support.test.espresso.NoMatchingRootException;
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewInteraction;
+import android.support.test.espresso.matcher.ViewMatchers;
+import android.widget.MenuPopupWindow.MenuDropDownListView;
+
+/**
+ * Espresso utility methods for the context menu.
+ */
+public final class ContextMenuUtils {
+ private ContextMenuUtils() {}
+
+ private static ViewInteraction onContextMenu() {
+ // TODO: Have more reliable way to get context menu.
+ return onView(ViewMatchers.isAssignableFrom(MenuDropDownListView.class))
+ .inRoot(withDecorView(hasFocus()));
+ }
+
+ /**
+ * Asserts that the context menu is displayed
+ *
+ * @throws AssertionError if the assertion fails
+ */
+ private static void assertContextMenuIsDisplayed() {
+ onContextMenu().check(matches(isDisplayed()));
+ }
+
+ /**
+ * Asserts that the context menu is not displayed
+ *
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertContextMenuIsNotDisplayed() {
+ try {
+ assertContextMenuIsDisplayed();
+ } catch (NoMatchingRootException | NoMatchingViewException | AssertionError e) {
+ return;
+ }
+ throw new AssertionError("Context menu is displayed");
+ }
+
+ /**
+ * Asserts that the context menu contains the specified item and the item has specified enabled
+ * state.
+ *
+ * @param itemLabel label of the item.
+ * @param enabled enabled state of the item.
+ * @throws AssertionError if the assertion fails
+ */
+ private static void asssertContextMenuContainsItemWithEnabledState(String itemLabel,
+ boolean enabled) {
+ onContextMenu().check(matches(
+ hasDescendant(allOf(
+ isAssignableFrom(ListMenuItemView.class),
+ enabled ? isEnabled() : not(isEnabled()),
+ hasDescendant(withText(itemLabel))))));
+ }
+
+ /**
+ * Asserts that the context menu contains the specified item and the item is enabled.
+ *
+ * @param itemLabel label of the item.
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertContextMenuContainsItemEnabled(String itemLabel) {
+ asssertContextMenuContainsItemWithEnabledState(itemLabel, true);
+ }
+
+ /**
+ * Asserts that the context menu contains the specified item and the item is disabled.
+ *
+ * @param itemLabel label of the item.
+ * @throws AssertionError if the assertion fails
+ */
+ public static void assertContextMenuContainsItemDisabled(String itemLabel) {
+ asssertContextMenuContainsItemWithEnabledState(itemLabel, false);
+ }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
index e51f2785..b8ea2de 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseClickAction.java
@@ -24,9 +24,9 @@
import android.support.test.espresso.action.GeneralClickAction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.action.MotionEvents.DownResultHolder;
-import android.support.test.espresso.action.PrecisionDescriber;
import android.support.test.espresso.action.Press;
import android.support.test.espresso.action.Tapper;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -35,6 +35,8 @@
*/
public final class MouseClickAction implements ViewAction {
private final GeneralClickAction mGeneralClickAction;
+ @MouseUiController.MouseButton
+ private final int mButton;
public enum CLICK implements Tapper {
TRIPLE {
@@ -86,8 +88,20 @@
};
public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider) {
- mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider,
- Press.PINPOINT);
+ this(tapper, coordinatesProvider, MotionEvent.BUTTON_PRIMARY);
+ }
+
+ /**
+ * Constructs MouseClickAction
+ *
+ * @param tapper the tapper
+ * @param coordinatesProvider the provider of the event coordinates
+ * @param button the mouse button used to send motion events
+ */
+ public MouseClickAction(Tapper tapper, CoordinatesProvider coordinatesProvider,
+ @MouseUiController.MouseButton int button) {
+ mGeneralClickAction = new GeneralClickAction(tapper, coordinatesProvider, Press.PINPOINT);
+ mButton = button;
}
@Override
@@ -102,7 +116,7 @@
@Override
public void perform(UiController uiController, View view) {
- mGeneralClickAction.perform(new MouseUiController(uiController), view);
+ mGeneralClickAction.perform(new MouseUiController(uiController, mButton), view);
long doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
if (0 < doubleTapTimeout) {
// Wait to avoid false gesture detection. Without this wait, consecutive clicks can be
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
index f1387f8..022be76 100644
--- a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
+++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
@@ -16,6 +16,12 @@
package android.widget.espresso;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
import android.support.test.espresso.InjectEventSecurityException;
import android.support.test.espresso.UiController;
import android.view.InputDevice;
@@ -26,11 +32,28 @@
* Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
* Note that this doesn't change the tool type.
*/
-public class MouseUiController implements UiController {
+public final class MouseUiController implements UiController {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({MotionEvent.BUTTON_PRIMARY, MotionEvent.BUTTON_SECONDARY, MotionEvent.BUTTON_TERTIARY})
+ public @interface MouseButton {}
+
private final UiController mUiController;
+ @MouseButton
+ private final int mButton;
public MouseUiController(UiController uiController) {
- mUiController = uiController;
+ this(uiController, MotionEvent.BUTTON_PRIMARY);
+ }
+
+ /**
+ * Constructs MouseUiController.
+ *
+ * @param uiController the uiController to wrap
+ * @param button the button to be used for generating input events.
+ */
+ public MouseUiController(UiController uiController, @MouseButton int button) {
+ mUiController = checkNotNull(uiController);
+ mButton = button;
}
@Override
@@ -40,9 +63,11 @@
@Override
public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException {
- // Modify the event to mimic mouse primary button event.
+ // Modify the event to mimic mouse event.
event.setSource(InputDevice.SOURCE_MOUSE);
- event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+ if (event.getActionMasked() != MotionEvent.ACTION_UP) {
+ event.setButtonState(mButton);
+ }
return mUiController.injectMotionEvent(event);
}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 54d5823..1dd6e17 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -26,6 +26,7 @@
import android.support.test.espresso.action.Tap;
import android.support.test.espresso.util.HumanReadables;
import android.text.Layout;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.Editor;
import android.widget.TextView;
@@ -63,8 +64,24 @@
* @param index The index of the TextView's text to click on.
*/
public static ViewAction mouseClickOnTextAtIndex(int index) {
+ return mouseClickOnTextAtIndex(index, MotionEvent.BUTTON_PRIMARY);
+ }
+
+ /**
+ * Returns an action that clicks by mouse on text at an index on the TextView.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ *
+ * @param index The index of the TextView's text to click on.
+ * @param button the mouse button to use.
+ */
+ public static ViewAction mouseClickOnTextAtIndex(int index,
+ @MouseUiController.MouseButton int button) {
return actionWithAssertions(
- new MouseClickAction(Tap.SINGLE, new TextCoordinates(index)));
+ new MouseClickAction(Tap.SINGLE, new TextCoordinates(index), button));
}
/**
diff --git a/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
new file mode 100644
index 0000000..49ae104
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/LineBreakBufferedWriterTest.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Tests for {@link IndentingPrintWriter}.
+ */
+public class LineBreakBufferedWriterTest extends TestCase {
+
+ private ByteArrayOutputStream mStream;
+ private RecordingWriter mWriter;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mWriter = new RecordingWriter();
+ }
+
+ public void testLessThanBufferSize() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 1000);
+
+ lw.println("Hello");
+ lw.println("World");
+ lw.println("Test");
+ lw.flush();
+
+ assertOutput("Hello\nWorld\nTest\n");
+ }
+
+ public void testMoreThanBufferSizeNoLineBreaks() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal = "aaaaaaaaaaaaaaa";
+ lw.print(literal);
+ lw.print(literal);
+ lw.flush();
+
+ // Have to manually inspect output.
+ List<String> result = mWriter.getStrings();
+ // Expect two strings.
+ assertEquals(2, result.size());
+ // Expect the strings to sum up to the original input.
+ assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length());
+ // Strings should only be a.
+ for (String s : result) {
+ for (int i = 0; i < s.length(); i++) {
+ assertEquals('a', s.charAt(i));
+ }
+ }
+ }
+
+ public void testMoreThanBufferSizeNoLineBreaksSingleString() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal = "aaaaaaaaaaaaaaa";
+ lw.print(literal + literal);
+ lw.flush();
+
+ // Have to manually inspect output.
+ List<String> result = mWriter.getStrings();
+ // Expect two strings.
+ assertEquals(2, result.size());
+ // Expect the strings to sum up to the original input.
+ assertEquals(2 * literal.length(), result.get(0).length() + result.get(1).length());
+ // Strings should only be a.
+ for (String s : result) {
+ for (int i = 0; i < s.length(); i++) {
+ assertEquals('a', s.charAt(i));
+ }
+ }
+ }
+
+ public void testMoreThanBufferSizeLineBreakBefore() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal1 = "aaaaaaaaaa\nbbbb";
+ String literal2 = "cccccccccc";
+ lw.print(literal1);
+ lw.print(literal2);
+ lw.flush();
+
+ assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
+ }
+
+ public void testMoreThanBufferSizeLineBreakBeforeSingleString() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal1 = "aaaaaaaaaa\nbbbb";
+ String literal2 = "cccccccccc";
+ lw.print(literal1 + literal2);
+ lw.flush();
+
+ assertOutput("aaaaaaaaaa", "bbbbcccccccccc");
+ }
+
+ public void testMoreThanBufferSizeLineBreakNew() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal1 = "aaaaaaaaaabbbbb";
+ String literal2 = "c\nd\nddddddddd";
+ lw.print(literal1);
+ lw.print(literal2);
+ lw.flush();
+
+ assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
+ }
+
+ public void testMoreThanBufferSizeLineBreakBeforeAndNew() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal1 = "aaaaaaaaaa\nbbbbb";
+ String literal2 = "c\nd\nddddddddd";
+ lw.print(literal1);
+ lw.print(literal2);
+ lw.flush();
+
+ assertOutput("aaaaaaaaaa\nbbbbbc\nd", "ddddddddd");
+ }
+
+ public void testMoreThanBufferSizeInt() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
+
+ int literal1 = 1234567890;
+ int literal2 = 987654321;
+ lw.print(literal1);
+ lw.print(literal2);
+ lw.flush();
+
+ assertOutput("123456789098765", "4321");
+ }
+
+ public void testMoreThanBufferSizeChar() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 15);
+
+ for(int i = 0; i < 10; i++) {
+ lw.print('$');
+ }
+ for(int i = 0; i < 10; i++) {
+ lw.print('%');
+ }
+ lw.flush();
+
+ assertOutput("$$$$$$$$$$%%%%%", "%%%%%");
+ }
+
+ public void testMoreThanBufferSizeLineBreakNewChars() {
+ final LineBreakBufferedWriter lw = new LineBreakBufferedWriter(mWriter, 20);
+
+ String literal1 = "aaaaaaaaaabbbbb";
+ String literal2 = "c\nd\nddddddddd";
+ lw.print(literal1.toCharArray());
+ lw.print(literal2.toCharArray());
+ lw.flush();
+
+ assertOutput("aaaaaaaaaabbbbbc\nd", "ddddddddd");
+ }
+
+ private void assertOutput(String... golden) {
+ List<String> goldList = createTestGolden(golden);
+ assertEquals(goldList, mWriter.getStrings());
+ }
+
+ private static List<String> createTestGolden(String... args) {
+ List<String> ret = new ArrayList<String>();
+ for (String s : args) {
+ ret.add(s);
+ }
+ return ret;
+ }
+
+ // A writer recording calls to write.
+ private final static class RecordingWriter extends Writer {
+
+ private List<String> strings = new ArrayList<String>();
+
+ public RecordingWriter() {
+ }
+
+ public List<String> getStrings() {
+ return strings;
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ strings.add(new String(cbuf, off, len));
+ }
+
+ @Override
+ public void flush() {
+ // Ignore.
+ }
+
+ @Override
+ public void close() {
+ // Ignore.
+ }
+ }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b4f88c33..999d47b 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -44,6 +44,7 @@
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="net_bt_stack" />
+ <group gid="wakelock" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 554b6f1..731bf42 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -344,7 +344,7 @@
<family>
<font weight="400" style="normal">NanumGothic.ttf</font>
</family>
- <family lang="und-Qaae">
+ <family lang="und-Zsye">
<font weight="400" style="normal">NotoColorEmoji.ttf</font>
</family>
<family>
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c05ea2e..704f0ce 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -38,13 +38,14 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* The main programming interface for the DRM framework. An application must instantiate this class
* to access DRM agents through the DRM framework.
*
*/
-public class DrmManagerClient {
+public class DrmManagerClient implements AutoCloseable {
/**
* Indicates that a request was successful or that no error occurred.
*/
@@ -61,6 +62,7 @@
HandlerThread mEventThread;
private static final String TAG = "DrmManagerClient";
+ private final AtomicBoolean mClosed = new AtomicBoolean();
private final CloseGuard mCloseGuard = CloseGuard.get();
static {
@@ -117,7 +119,6 @@
private int mUniqueId;
private long mNativeContext;
- private volatile boolean mReleased;
private Context mContext;
private InfoHandler mInfoHandler;
private EventHandler mEventHandler;
@@ -261,41 +262,47 @@
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- release();
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
}
/**
- * Releases resources associated with the current session of DrmManagerClient.
- *
- * It is considered good practice to call this method when the {@link DrmManagerClient} object
- * is no longer needed in your application. After release() is called,
- * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
+ * Releases resources associated with the current session of
+ * DrmManagerClient. It is considered good practice to call this method when
+ * the {@link DrmManagerClient} object is no longer needed in your
+ * application. After this method is called, {@link DrmManagerClient} is no
+ * longer usable since it has lost all of its required resource.
*/
- public void release() {
- if (mReleased) return;
- mReleased = true;
-
- if (mEventHandler != null) {
- mEventThread.quit();
- mEventThread = null;
- }
- if (mInfoHandler != null) {
- mInfoThread.quit();
- mInfoThread = null;
- }
- mEventHandler = null;
- mInfoHandler = null;
- mOnEventListener = null;
- mOnInfoListener = null;
- mOnErrorListener = null;
- _release(mUniqueId);
+ @Override
+ public void close() {
mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ if (mEventHandler != null) {
+ mEventThread.quit();
+ mEventThread = null;
+ }
+ if (mInfoHandler != null) {
+ mInfoThread.quit();
+ mInfoThread = null;
+ }
+ mEventHandler = null;
+ mInfoHandler = null;
+ mOnEventListener = null;
+ mOnInfoListener = null;
+ mOnErrorListener = null;
+ _release(mUniqueId);
+ }
+ }
+
+ /**
+ * @deprecated replaced by {@link #close()}.
+ */
+ @Deprecated
+ public void release() {
+ close();
}
/**
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index da58884..175c726 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -163,8 +163,11 @@
public boolean inPremultiplied;
/**
- * If dither is true, the decoder will attempt to dither the decoded
- * image.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+ * ignored.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if dither is
+ * true, the decoder will attempt to dither the decoded image.
*/
public boolean inDither;
@@ -308,7 +311,11 @@
public boolean inInputShareable;
/**
- * If inPreferQualityOverSpeed is set to true, the decoder will try to
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+ * ignored. The output will always be high quality.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if
+ * inPreferQualityOverSpeed is set to true, the decoder will try to
* decode the reconstructed image to a higher quality even at the
* expense of the decoding speed. Currently the field only affects JPEG
* decode, in the case of which a more accurate, but slightly slower,
@@ -347,8 +354,6 @@
*/
public byte[] inTempStorage;
- private native void requestCancel();
-
/**
* Flag to indicate that cancel has been called on this object. This
* is useful if there's an intermediary that wants to first decode the
@@ -359,16 +364,19 @@
public boolean mCancel;
/**
- * This can be called from another thread while this options object is
- * inside a decode... call. Calling this will notify the decoder that
- * it should cancel its operation. This is not guaranteed to cancel
- * the decode, but if it does, the decoder... operation will return
- * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this
+ * will not affect the decode, though it will still set mCancel.
+ *
+ * In {@link android.os.Build.VERSION_CODES#M} and below, if this can
+ * be called from another thread while this options object is inside
+ * a decode... call. Calling this will notify the decoder that it
+ * should cancel its operation. This is not guaranteed to cancel the
+ * decode, but if it does, the decoder... operation will return null,
+ * or if inJustDecodeBounds is true, will set outWidth/outHeight
* to -1
*/
public void requestCancelDecode() {
mCancel = true;
- requestCancel();
}
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5acc1a3..1cc5346 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -654,6 +654,12 @@
/**
* Return, in ctm, the current transformation matrix. This does not alter
* the matrix in the canvas, but just returns a copy of it.
+ *
+ * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+ * matrix when passed to a View or Drawable, as it is implementation defined where in the
+ * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+ * irrespective of the current matrix, or to track relevant transform state outside of the
+ * canvas.
*/
@Deprecated
public void getMatrix(@NonNull Matrix ctm) {
@@ -663,6 +669,12 @@
/**
* Return a new matrix with a copy of the canvas' current transformation
* matrix.
+ *
+ * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+ * matrix when passed to a View or Drawable, as it is implementation defined where in the
+ * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+ * irrespective of the current matrix, or to track relevant transform state outside of the
+ * canvas.
*/
@Deprecated
public final @NonNull Matrix getMatrix() {
@@ -812,6 +824,7 @@
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
+ @Deprecated
public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
}
@@ -829,6 +842,7 @@
* @deprecated Unlike all other clip calls this API does not respect the
* current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
+ @Deprecated
public boolean clipRegion(@NonNull Region region) {
return clipRegion(region, Region.Op.INTERSECT);
}
@@ -1079,11 +1093,12 @@
* (count >> 2).
* @param paint The paint used to draw the points
*/
- public void drawLines(@Size(min=4,multiple=2) float[] pts, int offset, int count, Paint paint) {
+ public void drawLines(@Size(multiple=4) @NonNull float[] pts, int offset, int count,
+ @NonNull Paint paint) {
native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
}
- public void drawLines(@Size(min=4,multiple=2) @NonNull float[] pts, @NonNull Paint paint) {
+ public void drawLines(@Size(multiple=4) @NonNull float[] pts, @NonNull Paint paint) {
drawLines(pts, 0, pts.length, paint);
}
@@ -1829,16 +1844,16 @@
* Draw the text in the array, with each character's origin specified by
* the pos array.
*
- * This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts. It also doesn't
- * handle supplementary characters (eg emoji).
- *
* @param text The text to be drawn
* @param index The index of the first character to draw
* @param count The number of characters to draw, starting from index.
* @param pos Array of [x,y] positions, used to position each
* character
* @param paint The paint used for the text (e.g. color, size, style)
+ *
+ * @deprecated This method does not support glyph composition and decomposition and
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*/
@Deprecated
public void drawPosText(@NonNull char[] text, int index, int count,
@@ -1856,13 +1871,13 @@
* Draw the text in the array, with each character's origin specified by
* the pos array.
*
- * This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts. It also doesn't
- * handle supplementary characters (eg emoji).
- *
* @param text The text to be drawn
* @param pos Array of [x,y] positions, used to position each character
* @param paint The paint used for the text (e.g. color, size, style)
+ *
+ * @deprecated This method does not support glyph composition and decomposition and
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*/
@Deprecated
public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1857345..84ca546 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,6 +19,7 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -140,6 +141,15 @@
/** Local, mutable animator set. */
private final AnimatorSet mAnimatorSet = new AnimatorSet();
+
+ private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+ new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateSelf();
+ }
+ };
+
/**
* The resources against which this drawable was created. Used to attempt
* to inflate animators if applyTheme() doesn't get called.
@@ -201,9 +211,6 @@
@Override
public void draw(Canvas canvas) {
mAnimatedVectorState.mVectorDrawable.draw(canvas);
- if (isStarted()) {
- invalidateSelf();
- }
}
@Override
@@ -486,6 +493,7 @@
* animators, or {@code null} if not available
*/
public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
+ @NonNull ValueAnimator.AnimatorUpdateListener updateListener,
@Nullable Resources res) {
// Check for uninflated animators. We can remove this after we add
// support for Animator.applyTheme(). See comments in inflate().
@@ -511,6 +519,17 @@
final Animator nextAnim = prepareLocalAnimator(i);
builder.with(nextAnim);
}
+
+ // Setup a value animator to get animation update callbacks.
+ long totalDuration = animatorSet.getTotalDuration();
+ ValueAnimator updateAnim = ValueAnimator.ofFloat(0f, 1f);
+ if (totalDuration == ValueAnimator.DURATION_INFINITE) {
+ updateAnim.setRepeatCount(ValueAnimator.INFINITE);
+ } else {
+ updateAnim.setDuration(totalDuration);
+ }
+ updateAnim.addUpdateListener(updateListener);
+ builder.with(updateAnim);
}
}
@@ -603,7 +622,7 @@
@NonNull
private void ensureAnimatorSet() {
if (!mHasAnimatorSet) {
- mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mUpdateListener, mRes);
mHasAnimatorSet = true;
mRes = null;
}
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/graphics/java/android/graphics/drawable/Icon.aidl
similarity index 67%
copy from core/java/android/view/IDockDividerVisibilityListener.aidl
copy to graphics/java/android/graphics/drawable/Icon.aidl
index a7d5cda..b82cfc4 100644
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ b/graphics/java/android/graphics/drawable/Icon.aidl
@@ -14,14 +14,6 @@
* limitations under the License.
*/
-package android.view;
+package android.graphics.drawable;
-/**
- * Listener for showing/hiding of the dock divider. Will fire when an app is shown in side by side
- * mode and a divider should be shown.
- *
- * @hide
- */
-oneway interface IDockDividerVisibilityListener {
- void onDockDividerVisibilityChanged(boolean visible);
-}
+parcelable Icon;
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 3761a99..6526021 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -20,15 +20,9 @@
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Insets;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
@@ -38,7 +32,6 @@
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
import android.util.Log;
-import android.util.MathUtils;
import android.util.PathParser;
import android.util.Xml;
@@ -48,6 +41,8 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Stack;
@@ -196,21 +191,6 @@
private static final String SHAPE_PATH = "path";
private static final String SHAPE_VECTOR = "vector";
- private static final int LINECAP_BUTT = 0;
- private static final int LINECAP_ROUND = 1;
- private static final int LINECAP_SQUARE = 2;
-
- private static final int LINEJOIN_MITER = 0;
- private static final int LINEJOIN_ROUND = 1;
- private static final int LINEJOIN_BEVEL = 2;
-
- // Cap the bitmap size, such that it won't hurt the performance too much
- // and it won't crash due to a very large scale.
- // The drawable will look blurry above this size.
- private static final int MAX_CACHED_BITMAP_SIZE = 2048;
-
- private static final boolean DBG_VECTOR_DRAWABLE = false;
-
private VectorDrawableState mVectorState;
private PorterDuffColorFilter mTintFilter;
@@ -218,10 +198,6 @@
private boolean mMutated;
- // AnimatedVectorDrawable needs to turn off the cache all the time, otherwise,
- // caching the bitmap by default is allowed.
- private boolean mAllowCaching = true;
-
/** The density of the display on which this drawable will be rendered. */
private int mTargetDensity;
@@ -235,8 +211,6 @@
private boolean mDpiScaledDirty = true;
// Temp variable, only for saving "new" operation at the draw() time.
- private final float[] mTmpFloats = new float[9];
- private final Matrix mTmpMatrix = new Matrix();
private final Rect mTmpBounds = new Rect();
public VectorDrawable() {
@@ -249,7 +223,6 @@
*/
private VectorDrawable(@NonNull VectorDrawableState state, @Nullable Resources res) {
mVectorState = state;
-
updateLocalState(res);
}
@@ -262,7 +235,7 @@
* displayed, or {@code null} to use the constant state defaults
*/
private void updateLocalState(Resources res) {
- final int density = Drawable.resolveDensity(res, mVectorState.mVPathRenderer.mDensity);
+ final int density = Drawable.resolveDensity(res, mVectorState.mDensity);
if (mTargetDensity != density) {
mTargetDensity = density;
mDpiScaledDirty = true;
@@ -289,7 +262,7 @@
}
Object getTargetByName(String name) {
- return mVectorState.mVPathRenderer.mVGTargetsMap.get(name);
+ return mVectorState.mVGTargetsMap.get(name);
}
@Override
@@ -310,61 +283,23 @@
// Color filters always override tint filters.
final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
-
- // The imageView can scale the canvas in different ways, in order to
- // avoid blurry scaling, we have to draw into a bitmap with exact pixel
- // size first. This bitmap size is determined by the bounds and the
- // canvas scale.
- canvas.getMatrix(mTmpMatrix);
- mTmpMatrix.getValues(mTmpFloats);
- float canvasScaleX = Math.abs(mTmpFloats[Matrix.MSCALE_X]);
- float canvasScaleY = Math.abs(mTmpFloats[Matrix.MSCALE_Y]);
- int scaledWidth = (int) (mTmpBounds.width() * canvasScaleX);
- int scaledHeight = (int) (mTmpBounds.height() * canvasScaleY);
- scaledWidth = Math.min(MAX_CACHED_BITMAP_SIZE, scaledWidth);
- scaledHeight = Math.min(MAX_CACHED_BITMAP_SIZE, scaledHeight);
-
- if (scaledWidth <= 0 || scaledHeight <= 0) {
- return;
- }
-
- final int saveCount = canvas.save();
- canvas.translate(mTmpBounds.left, mTmpBounds.top);
-
- // Handle RTL mirroring.
- final boolean needMirroring = needMirroring();
- if (needMirroring) {
- canvas.translate(mTmpBounds.width(), 0);
- canvas.scale(-1.0f, 1.0f);
- }
-
- // At this point, canvas has been translated to the right position.
- // And we use this bound for the destination rect for the drawBitmap, so
- // we offset to (0, 0);
- mTmpBounds.offsetTo(0, 0);
-
- mVectorState.createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
- if (!mAllowCaching) {
- mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
- } else {
- if (!mVectorState.canReuseCache()) {
- mVectorState.updateCachedBitmap(scaledWidth, scaledHeight);
- mVectorState.updateCacheStates();
- }
- }
- mVectorState.drawCachedBitmapWithRootAlpha(canvas, colorFilter, mTmpBounds);
- canvas.restoreToCount(saveCount);
+ final long colorFilterNativeInstance = colorFilter == null ? 0 :
+ colorFilter.native_instance;
+ boolean canReuseCache = mVectorState.canReuseCache();
+ nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
+ colorFilterNativeInstance, mTmpBounds, needMirroring(),
+ canReuseCache);
}
+
@Override
public int getAlpha() {
- return mVectorState.mVPathRenderer.getRootAlpha();
+ return (int) (mVectorState.getAlpha() * 255);
}
@Override
public void setAlpha(int alpha) {
- if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
- mVectorState.mVPathRenderer.setRootAlpha(alpha);
+ if (mVectorState.setAlpha(alpha / 255f)) {
invalidateSelf();
}
}
@@ -410,7 +345,7 @@
boolean changed = false;
final VectorDrawableState state = mVectorState;
- if (state.mVPathRenderer != null && state.mVPathRenderer.onStateChange(stateSet)) {
+ if (state.onStateChange(stateSet)) {
changed = true;
state.mCacheDirty = true;
}
@@ -457,16 +392,15 @@
* from the source density against which the constant state was loaded.
*/
void computeVectorSize() {
- final VPathRenderer pathRenderer = mVectorState.mVPathRenderer;
- final Insets opticalInsets = pathRenderer.mOpticalInsets;
+ final Insets opticalInsets = mVectorState.mOpticalInsets;
- final int sourceDensity = pathRenderer.mDensity;
+ final int sourceDensity = mVectorState.mDensity;
final int targetDensity = mTargetDensity;
if (targetDensity != sourceDensity) {
mDpiScaledWidth = Drawable.scaleFromDensity(
- (int) pathRenderer.mBaseWidth, sourceDensity, targetDensity, true);
+ (int) mVectorState.mBaseWidth, sourceDensity, targetDensity, true);
mDpiScaledHeight = Drawable.scaleFromDensity(
- (int) pathRenderer.mBaseHeight,sourceDensity, targetDensity, true);
+ (int) mVectorState.mBaseHeight,sourceDensity, targetDensity, true);
final int left = Drawable.scaleFromDensity(
opticalInsets.left, sourceDensity, targetDensity, false);
final int right = Drawable.scaleFromDensity(
@@ -477,8 +411,8 @@
opticalInsets.bottom, sourceDensity, targetDensity, false);
mDpiScaledInsets = Insets.of(left, top, right, bottom);
} else {
- mDpiScaledWidth = (int) pathRenderer.mBaseWidth;
- mDpiScaledHeight = (int) pathRenderer.mBaseHeight;
+ mDpiScaledWidth = (int) mVectorState.mBaseWidth;
+ mDpiScaledHeight = (int) mVectorState.mBaseHeight;
mDpiScaledInsets = opticalInsets;
}
@@ -499,8 +433,7 @@
return;
}
- final VPathRenderer path = state.mVPathRenderer;
- final boolean changedDensity = path.setDensity(
+ final boolean changedDensity = mVectorState.setDensity(
Drawable.resolveDensity(t.getResources(), 0));
mDpiScaledDirty |= changedDensity;
@@ -511,7 +444,7 @@
state.mCacheDirty = true;
updateStateFromTypedArray(a);
} catch (XmlPullParserException e) {
- rethrowAsRuntimeException(e);
+ throw new RuntimeException(e);
} finally {
a.recycle();
}
@@ -525,8 +458,8 @@
state.mTint = state.mTint.obtainForTheme(t);
}
- if (path != null && path.canApplyTheme()) {
- path.applyTheme(t);
+ if (mVectorState != null && mVectorState.canApplyTheme()) {
+ mVectorState.applyTheme(t);
}
// Update local properties.
@@ -540,17 +473,17 @@
* @hide
*/
public float getPixelSize() {
- if (mVectorState == null || mVectorState.mVPathRenderer == null ||
- mVectorState.mVPathRenderer.mBaseWidth == 0 ||
- mVectorState.mVPathRenderer.mBaseHeight == 0 ||
- mVectorState.mVPathRenderer.mViewportHeight == 0 ||
- mVectorState.mVPathRenderer.mViewportWidth == 0) {
+ if (mVectorState == null ||
+ mVectorState.mBaseWidth == 0 ||
+ mVectorState.mBaseHeight == 0 ||
+ mVectorState.mViewportHeight == 0 ||
+ mVectorState.mViewportWidth == 0) {
return 1; // fall back to 1:1 pixel mapping.
}
- float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
- float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
- float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
- float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+ float intrinsicWidth = mVectorState.mBaseWidth;
+ float intrinsicHeight = mVectorState.mBaseHeight;
+ float viewportWidth = mVectorState.mViewportWidth;
+ float viewportHeight = mVectorState.mViewportHeight;
float scaleX = viewportWidth / intrinsicWidth;
float scaleY = viewportHeight / intrinsicHeight;
return Math.min(scaleX, scaleY);
@@ -582,20 +515,20 @@
return null;
}
- private static int applyAlpha(int color, float alpha) {
- int alphaBytes = Color.alpha(color);
- color &= 0x00FFFFFF;
- color |= ((int) (alphaBytes * alpha)) << 24;
- return color;
- }
-
@Override
public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Theme theme)
throws XmlPullParserException, IOException {
+ if (mVectorState.mRootGroup != null || mVectorState.mNativeRendererPtr != 0) {
+ // This VD has been used to display other VD resource content, clean up.
+ mVectorState.mRootGroup = new VGroup();
+ if (mVectorState.mNativeRendererPtr != 0) {
+ nDestroyRenderer(mVectorState.mNativeRendererPtr);
+ }
+ mVectorState.mNativeRendererPtr = nCreateRenderer(mVectorState.mRootGroup.mNativePtr);
+ }
final VectorDrawableState state = mVectorState;
- state.mVPathRenderer = new VPathRenderer();
- state.mVPathRenderer.setDensity(Drawable.resolveDensity(r, 0));
+ state.setDensity(Drawable.resolveDensity(r, 0));
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
updateStateFromTypedArray(a);
@@ -612,7 +545,6 @@
private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
final VectorDrawableState state = mVectorState;
- final VPathRenderer pathRenderer = state.mVPathRenderer;
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
@@ -633,63 +565,63 @@
state.mAutoMirrored = a.getBoolean(
R.styleable.VectorDrawable_autoMirrored, state.mAutoMirrored);
- pathRenderer.mViewportWidth = a.getFloat(
- R.styleable.VectorDrawable_viewportWidth, pathRenderer.mViewportWidth);
- pathRenderer.mViewportHeight = a.getFloat(
- R.styleable.VectorDrawable_viewportHeight, pathRenderer.mViewportHeight);
+ float viewportWidth = a.getFloat(
+ R.styleable.VectorDrawable_viewportWidth, state.mViewportWidth);
+ float viewportHeight = a.getFloat(
+ R.styleable.VectorDrawable_viewportHeight, state.mViewportHeight);
+ state.setViewportSize(viewportWidth, viewportHeight);
- if (pathRenderer.mViewportWidth <= 0) {
+ if (state.mViewportWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires viewportWidth > 0");
- } else if (pathRenderer.mViewportHeight <= 0) {
+ } else if (state.mViewportHeight <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires viewportHeight > 0");
}
- pathRenderer.mBaseWidth = a.getDimension(
- R.styleable.VectorDrawable_width, pathRenderer.mBaseWidth);
- pathRenderer.mBaseHeight = a.getDimension(
- R.styleable.VectorDrawable_height, pathRenderer.mBaseHeight);
+ state.mBaseWidth = a.getDimension(
+ R.styleable.VectorDrawable_width, state.mBaseWidth);
+ state.mBaseHeight = a.getDimension(
+ R.styleable.VectorDrawable_height, state.mBaseHeight);
- if (pathRenderer.mBaseWidth <= 0) {
+ if (state.mBaseWidth <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires width > 0");
- } else if (pathRenderer.mBaseHeight <= 0) {
+ } else if (state.mBaseHeight <= 0) {
throw new XmlPullParserException(a.getPositionDescription() +
"<vector> tag requires height > 0");
}
final int insetLeft = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetLeft, pathRenderer.mOpticalInsets.left);
+ R.styleable.VectorDrawable_opticalInsetLeft, state.mOpticalInsets.left);
final int insetTop = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetTop, pathRenderer.mOpticalInsets.top);
+ R.styleable.VectorDrawable_opticalInsetTop, state.mOpticalInsets.top);
final int insetRight = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetRight, pathRenderer.mOpticalInsets.right);
+ R.styleable.VectorDrawable_opticalInsetRight, state.mOpticalInsets.right);
final int insetBottom = a.getDimensionPixelOffset(
- R.styleable.VectorDrawable_opticalInsetBottom, pathRenderer.mOpticalInsets.bottom);
- pathRenderer.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
+ R.styleable.VectorDrawable_opticalInsetBottom, state.mOpticalInsets.bottom);
+ state.mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
final float alphaInFloat = a.getFloat(
- R.styleable.VectorDrawable_alpha, pathRenderer.getAlpha());
- pathRenderer.setAlpha(alphaInFloat);
+ R.styleable.VectorDrawable_alpha, state.getAlpha());
+ state.setAlpha(alphaInFloat);
final String name = a.getString(R.styleable.VectorDrawable_name);
if (name != null) {
- pathRenderer.mRootName = name;
- pathRenderer.mVGTargetsMap.put(name, pathRenderer);
+ state.mRootName = name;
+ state.mVGTargetsMap.put(name, state);
}
}
private void inflateChildElements(Resources res, XmlPullParser parser, AttributeSet attrs,
Theme theme) throws XmlPullParserException, IOException {
final VectorDrawableState state = mVectorState;
- final VPathRenderer pathRenderer = state.mVPathRenderer;
boolean noPathTag = true;
// Use a stack to help to build the group tree.
// The top of the stack is always the current group.
final Stack<VGroup> groupStack = new Stack<VGroup>();
- groupStack.push(pathRenderer.mRootGroup);
+ groupStack.push(state.mRootGroup);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
@@ -702,7 +634,7 @@
path.inflate(res, attrs, theme);
currentGroup.addChild(path);
if (path.getPathName() != null) {
- pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ state.mVGTargetsMap.put(path.getPathName(), path);
}
noPathTag = false;
state.mChangingConfigurations |= path.mChangingConfigurations;
@@ -711,7 +643,7 @@
path.inflate(res, attrs, theme);
currentGroup.addChild(path);
if (path.getPathName() != null) {
- pathRenderer.mVGTargetsMap.put(path.getPathName(), path);
+ state.mVGTargetsMap.put(path.getPathName(), path);
}
state.mChangingConfigurations |= path.mChangingConfigurations;
} else if (SHAPE_GROUP.equals(tagName)) {
@@ -720,7 +652,7 @@
currentGroup.addChild(newChildGroup);
groupStack.push(newChildGroup);
if (newChildGroup.getGroupName() != null) {
- pathRenderer.mVGTargetsMap.put(newChildGroup.getGroupName(),
+ state.mVGTargetsMap.put(newChildGroup.getGroupName(),
newChildGroup);
}
state.mChangingConfigurations |= newChildGroup.mChangingConfigurations;
@@ -734,11 +666,6 @@
eventType = parser.next();
}
- // Print the tree out for debug.
- if (DBG_VECTOR_DRAWABLE) {
- pathRenderer.printGroupTree();
- }
-
if (noPathTag) {
final StringBuffer tag = new StringBuffer();
@@ -757,7 +684,7 @@
}
void setAllowCaching(boolean allowCaching) {
- mAllowCaching = allowCaching;
+ nSetAllowCaching(mVectorState.getNativeRenderer(), allowCaching);
}
private boolean needMirroring() {
@@ -778,84 +705,68 @@
}
private static class VectorDrawableState extends ConstantState {
+ // Variables below need to be copied (deep copy if applicable) for mutation.
int[] mThemeAttrs;
int mChangingConfigurations;
- VPathRenderer mVPathRenderer;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
boolean mAutoMirrored;
- Bitmap mCachedBitmap;
+ float mBaseWidth = 0;
+ float mBaseHeight = 0;
+ float mViewportWidth = 0;
+ float mViewportHeight = 0;
+ Insets mOpticalInsets = Insets.NONE;
+ String mRootName = null;
+ VGroup mRootGroup;
+ long mNativeRendererPtr;
+
+ int mDensity = DisplayMetrics.DENSITY_DEFAULT;
+ final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
+
+ // Fields for cache
int[] mCachedThemeAttrs;
ColorStateList mCachedTint;
Mode mCachedTintMode;
- int mCachedRootAlpha;
boolean mCachedAutoMirrored;
boolean mCacheDirty;
- /** Temporary paint object used to draw cached bitmaps. */
- Paint mTempPaint;
// Deep copy for mutate() or implicitly mutate.
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
mThemeAttrs = copy.mThemeAttrs;
mChangingConfigurations = copy.mChangingConfigurations;
- mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
mTint = copy.mTint;
mTintMode = copy.mTintMode;
mAutoMirrored = copy.mAutoMirrored;
+ mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+ mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
+
+ mBaseWidth = copy.mBaseWidth;
+ mBaseHeight = copy.mBaseHeight;
+ setViewportSize(copy.mViewportWidth, copy.mViewportHeight);
+ mOpticalInsets = copy.mOpticalInsets;
+
+ mRootName = copy.mRootName;
+ mDensity = copy.mDensity;
+ if (copy.mRootName != null) {
+ mVGTargetsMap.put(copy.mRootName, this);
+ }
}
}
- public void drawCachedBitmapWithRootAlpha(Canvas canvas, ColorFilter filter,
- Rect originalBounds) {
- // The bitmap's size is the same as the bounds.
- final Paint p = getPaint(filter);
- canvas.drawBitmap(mCachedBitmap, null, originalBounds, p);
- }
-
- public boolean hasTranslucentRoot() {
- return mVPathRenderer.getRootAlpha() < 255;
- }
-
- /**
- * @return null when there is no need for alpha paint.
- */
- public Paint getPaint(ColorFilter filter) {
- if (!hasTranslucentRoot() && filter == null) {
- return null;
+ @Override
+ public void finalize() throws Throwable {
+ if (mNativeRendererPtr != 0) {
+ nDestroyRenderer(mNativeRendererPtr);
+ mNativeRendererPtr = 0;
}
-
- if (mTempPaint == null) {
- mTempPaint = new Paint();
- mTempPaint.setFilterBitmap(true);
- }
- mTempPaint.setAlpha(mVPathRenderer.getRootAlpha());
- mTempPaint.setColorFilter(filter);
- return mTempPaint;
+ super.finalize();
}
- public void updateCachedBitmap(int width, int height) {
- mCachedBitmap.eraseColor(Color.TRANSPARENT);
- Canvas tmpCanvas = new Canvas(mCachedBitmap);
- mVPathRenderer.draw(tmpCanvas, width, height, null);
- }
- public void createCachedBitmapIfNeeded(int width, int height) {
- if (mCachedBitmap == null || !canReuseBitmap(width, height)) {
- mCachedBitmap = Bitmap.createBitmap(width, height,
- Bitmap.Config.ARGB_8888);
- mCacheDirty = true;
- }
-
- }
-
- public boolean canReuseBitmap(int width, int height) {
- if (width == mCachedBitmap.getWidth()
- && height == mCachedBitmap.getHeight()) {
- return true;
- }
- return false;
+ long getNativeRenderer() {
+ return mNativeRendererPtr;
}
public boolean canReuseCache() {
@@ -863,10 +774,10 @@
&& mCachedThemeAttrs == mThemeAttrs
&& mCachedTint == mTint
&& mCachedTintMode == mTintMode
- && mCachedAutoMirrored == mAutoMirrored
- && mCachedRootAlpha == mVPathRenderer.getRootAlpha()) {
+ && mCachedAutoMirrored == mAutoMirrored) {
return true;
}
+ updateCacheStates();
return false;
}
@@ -876,21 +787,25 @@
mCachedThemeAttrs = mThemeAttrs;
mCachedTint = mTint;
mCachedTintMode = mTintMode;
- mCachedRootAlpha = mVPathRenderer.getRootAlpha();
mCachedAutoMirrored = mAutoMirrored;
mCacheDirty = false;
}
+ public void applyTheme(Theme t) {
+ mRootGroup.applyTheme(t);
+ }
+
@Override
public boolean canApplyTheme() {
return mThemeAttrs != null
- || (mVPathRenderer != null && mVPathRenderer.canApplyTheme())
+ || (mRootGroup != null && mRootGroup.canApplyTheme())
|| (mTint != null && mTint.canApplyTheme())
|| super.canApplyTheme();
}
public VectorDrawableState() {
- mVPathRenderer = new VPathRenderer();
+ mRootGroup = new VGroup();
+ mNativeRendererPtr = nCreateRenderer(mRootGroup.mNativePtr);
}
@Override
@@ -911,80 +826,13 @@
public boolean isStateful() {
return (mTint != null && mTint.isStateful())
- || (mVPathRenderer != null && mVPathRenderer.isStateful());
- }
- }
-
- private static class VPathRenderer {
- /* Right now the internal data structure is organized as a tree.
- * Each node can be a group node, or a path.
- * A group node can have groups or paths as children, but a path node has
- * no children.
- * One example can be:
- * Root Group
- * / | \
- * Group Path Group
- * / \ |
- * Path Path Path
- *
- */
- // Variables that only used temporarily inside the draw() call, so there
- // is no need for deep copying.
- private final TempState mTempState = new TempState();
-
- /////////////////////////////////////////////////////
- // Variables below need to be copied (deep copy if applicable) for mutation.
- private int mChangingConfigurations;
- private final VGroup mRootGroup;
- float mBaseWidth = 0;
- float mBaseHeight = 0;
- float mViewportWidth = 0;
- float mViewportHeight = 0;
- Insets mOpticalInsets = Insets.NONE;
- int mRootAlpha = 0xFF;
- String mRootName = null;
-
- int mDensity = DisplayMetrics.DENSITY_DEFAULT;
-
- final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
-
- public VPathRenderer() {
- mRootGroup = new VGroup();
+ || (mRootGroup != null && mRootGroup.isStateful());
}
- public void setRootAlpha(int alpha) {
- mRootAlpha = alpha;
- }
-
- public int getRootAlpha() {
- return mRootAlpha;
- }
-
- // setAlpha() and getAlpha() are used mostly for animation purpose, since
- // Animator like to use alpha from 0 to 1.
- public void setAlpha(float alpha) {
- setRootAlpha((int) (alpha * 255));
- }
-
- @SuppressWarnings("unused")
- public float getAlpha() {
- return getRootAlpha() / 255.0f;
- }
-
- public VPathRenderer(VPathRenderer copy) {
- mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
- mBaseWidth = copy.mBaseWidth;
- mBaseHeight = copy.mBaseHeight;
- mViewportWidth = copy.mViewportWidth;
- mViewportHeight = copy.mViewportHeight;
- mOpticalInsets = copy.mOpticalInsets;
- mChangingConfigurations = copy.mChangingConfigurations;
- mRootAlpha = copy.mRootAlpha;
- mRootName = copy.mRootName;
- mDensity = copy.mDensity;
- if (copy.mRootName != null) {
- mVGTargetsMap.put(copy.mRootName, this);
- }
+ void setViewportSize(float viewportWidth, float viewportHeight) {
+ mViewportWidth = viewportWidth;
+ mViewportHeight = viewportHeight;
+ nSetRendererViewportSize(getNativeRenderer(), viewportWidth, viewportHeight);
}
public final boolean setDensity(int targetDensity) {
@@ -1012,68 +860,50 @@
mOpticalInsets = Insets.of(insetLeft, insetTop, insetRight, insetBottom);
}
- public boolean canApplyTheme() {
- return mRootGroup.canApplyTheme();
- }
-
- public void applyTheme(Theme t) {
- mRootGroup.applyTheme(t);
- }
-
public boolean onStateChange(int[] stateSet) {
return mRootGroup.onStateChange(stateSet);
}
- public boolean isStateful() {
- return mRootGroup.isStateful();
+ /**
+ * setAlpha() and getAlpha() are used mostly for animation purpose. Return true if alpha
+ * has changed.
+ */
+ public boolean setAlpha(float alpha) {
+ return nSetRootAlpha(mNativeRendererPtr, alpha);
}
- public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
- final float scaleX = w / mViewportWidth;
- final float scaleY = h / mViewportHeight;
- mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
- }
-
- public void printGroupTree() {
- mRootGroup.printGroupTree("");
+ @SuppressWarnings("unused")
+ public float getAlpha() {
+ return nGetRootAlpha(mNativeRendererPtr);
}
}
private static class VGroup implements VObject {
- private static final String GROUP_INDENT = " ";
+ private static final int ROTATE_INDEX = 0;
+ private static final int PIVOT_X_INDEX = 1;
+ private static final int PIVOT_Y_INDEX = 2;
+ private static final int SCALE_X_INDEX = 3;
+ private static final int SCALE_Y_INDEX = 4;
+ private static final int TRANSLATE_X_INDEX = 5;
+ private static final int TRANSLATE_Y_INDEX = 6;
+ private static final int TRANSFORM_PROPERTY_COUNT = 7;
- // mStackedMatrix is only used temporarily when drawing, it combines all
- // the parents' local matrices with the current one.
- private final Matrix mStackedMatrix = new Matrix();
-
+ // Temp array to store transform values obtained from native.
+ private float[] mTransform;
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private final ArrayList<VObject> mChildren = new ArrayList<>();
-
- private float mRotate = 0;
- private float mPivotX = 0;
- private float mPivotY = 0;
- private float mScaleX = 1;
- private float mScaleY = 1;
- private float mTranslateX = 0;
- private float mTranslateY = 0;
private boolean mIsStateful;
// mLocalMatrix is updated based on the update of transformation information,
// either parsed from the XML or by animation.
- private final Matrix mLocalMatrix = new Matrix();
private int mChangingConfigurations;
private int[] mThemeAttrs;
private String mGroupName = null;
+ private long mNativePtr = 0;
public VGroup(VGroup copy, ArrayMap<String, Object> targetsMap) {
- mRotate = copy.mRotate;
- mPivotX = copy.mPivotX;
- mPivotY = copy.mPivotY;
- mScaleX = copy.mScaleX;
- mScaleY = copy.mScaleY;
- mTranslateX = copy.mTranslateX;
- mTranslateY = copy.mTranslateY;
+
mIsStateful = copy.mIsStateful;
mThemeAttrs = copy.mThemeAttrs;
mGroupName = copy.mGroupName;
@@ -1081,15 +911,14 @@
if (mGroupName != null) {
targetsMap.put(mGroupName, this);
}
-
- mLocalMatrix.set(copy.mLocalMatrix);
+ mNativePtr = nCreateGroup(copy.mNativePtr);
final ArrayList<VObject> children = copy.mChildren;
for (int i = 0; i < children.size(); i++) {
final VObject copyChild = children.get(i);
if (copyChild instanceof VGroup) {
final VGroup copyGroup = (VGroup) copyChild;
- mChildren.add(new VGroup(copyGroup, targetsMap));
+ addChild(new VGroup(copyGroup, targetsMap));
} else {
final VPath newPath;
if (copyChild instanceof VFullPath) {
@@ -1099,7 +928,7 @@
} else {
throw new IllegalStateException("Unknown object in the tree!");
}
- mChildren.add(newPath);
+ addChild(newPath);
if (newPath.mPathName != null) {
targetsMap.put(newPath.mPathName, newPath);
}
@@ -1108,43 +937,23 @@
}
public VGroup() {
+ mNativePtr = nCreateGroup();
}
public String getGroupName() {
return mGroupName;
}
- public Matrix getLocalMatrix() {
- return mLocalMatrix;
- }
-
public void addChild(VObject child) {
+ nAddChild(mNativePtr, child.getNativePtr());
mChildren.add(child);
mIsStateful |= child.isStateful();
}
@Override
- public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
- ColorFilter filter, float scaleX, float scaleY) {
- // Calculate current group's matrix by preConcat the parent's and
- // and the current one on the top of the stack.
- // Basically the Mfinal = Mviewport * M0 * M1 * M2;
- // Mi the local matrix at level i of the group tree.
- mStackedMatrix.set(currentMatrix);
- mStackedMatrix.preConcat(mLocalMatrix);
-
- // Save the current clip information, which is local to this group.
- canvas.save();
-
- // Draw the group tree in the same order as the XML file.
- for (int i = 0, count = mChildren.size(); i < count; i++) {
- final VObject child = mChildren.get(i);
- child.draw(canvas, temp, mStackedMatrix, filter, scaleX, scaleY);
- }
-
- // Restore the previous clip information.
- canvas.restore();
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
@@ -1155,27 +964,43 @@
a.recycle();
}
- private void updateStateFromTypedArray(TypedArray a) {
+ void updateStateFromTypedArray(TypedArray a) {
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
mThemeAttrs = a.extractThemeAttrs();
-
- mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
- mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
- mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
- mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
- mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
- mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
- mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ if (mTransform == null) {
+ // Lazy initialization: If the group is created through copy constructor, this may
+ // never get called.
+ mTransform = new float[TRANSFORM_PROPERTY_COUNT];
+ }
+ boolean success = nGetGroupProperties(mNativePtr, mTransform, TRANSFORM_PROPERTY_COUNT);
+ if (!success) {
+ throw new RuntimeException("Error: inconsistent property count");
+ }
+ float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation,
+ mTransform[ROTATE_INDEX]);
+ float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX,
+ mTransform[PIVOT_X_INDEX]);
+ float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY,
+ mTransform[PIVOT_Y_INDEX]);
+ float scaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX,
+ mTransform[SCALE_X_INDEX]);
+ float scaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY,
+ mTransform[SCALE_Y_INDEX]);
+ float translateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX,
+ mTransform[TRANSLATE_X_INDEX]);
+ float translateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY,
+ mTransform[TRANSLATE_Y_INDEX]);
final String groupName = a.getString(R.styleable.VectorDrawableGroup_name);
if (groupName != null) {
mGroupName = groupName;
+ nSetName(mNativePtr, mGroupName);
}
-
- updateLocalMatrix();
+ nUpdateGroupProperties(mNativePtr, rotate, pivotX, pivotY, scaleX, scaleY,
+ translateX, translateY);
}
@Override
@@ -1216,6 +1041,16 @@
}
@Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ super.finalize();
+ }
+
+
+ @Override
public void applyTheme(Theme t) {
if (mThemeAttrs != null) {
final TypedArray a = t.resolveAttributes(mThemeAttrs,
@@ -1236,124 +1071,75 @@
}
}
- private void updateLocalMatrix() {
- // The order we apply is the same as the
- // RenderNode.cpp::applyViewPropertyTransforms().
- mLocalMatrix.reset();
- mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
- mLocalMatrix.postScale(mScaleX, mScaleY);
- mLocalMatrix.postRotate(mRotate, 0, 0);
- mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
- }
-
- public void printGroupTree(String indent) {
- Log.v(LOGTAG, indent + "group:" + getGroupName() + " rotation is " + mRotate);
- Log.v(LOGTAG, indent + "matrix:" + getLocalMatrix().toString());
-
- final int count = mChildren.size();
- if (count > 0) {
- indent += GROUP_INDENT;
- }
-
- // Then print all the children groups.
- for (int i = 0; i < count; i++) {
- final VObject child = mChildren.get(i);
- if (child instanceof VGroup) {
- ((VGroup) child).printGroupTree(indent);
- }
- }
- }
-
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public float getRotation() {
- return mRotate;
+ return nGetRotation(mNativePtr);
}
@SuppressWarnings("unused")
public void setRotation(float rotation) {
- if (rotation != mRotate) {
- mRotate = rotation;
- updateLocalMatrix();
- }
+ nSetRotation(mNativePtr, rotation);
}
@SuppressWarnings("unused")
public float getPivotX() {
- return mPivotX;
+ return nGetPivotX(mNativePtr);
}
@SuppressWarnings("unused")
public void setPivotX(float pivotX) {
- if (pivotX != mPivotX) {
- mPivotX = pivotX;
- updateLocalMatrix();
- }
+ nSetPivotX(mNativePtr, pivotX);
}
@SuppressWarnings("unused")
public float getPivotY() {
- return mPivotY;
+ return nGetPivotY(mNativePtr);
}
@SuppressWarnings("unused")
public void setPivotY(float pivotY) {
- if (pivotY != mPivotY) {
- mPivotY = pivotY;
- updateLocalMatrix();
- }
+ nSetPivotY(mNativePtr, pivotY);
}
@SuppressWarnings("unused")
public float getScaleX() {
- return mScaleX;
+ return nGetScaleX(mNativePtr);
}
@SuppressWarnings("unused")
public void setScaleX(float scaleX) {
- if (scaleX != mScaleX) {
- mScaleX = scaleX;
- updateLocalMatrix();
- }
+ nSetScaleX(mNativePtr, scaleX);
}
@SuppressWarnings("unused")
public float getScaleY() {
- return mScaleY;
+ return nGetScaleY(mNativePtr);
}
@SuppressWarnings("unused")
public void setScaleY(float scaleY) {
- if (scaleY != mScaleY) {
- mScaleY = scaleY;
- updateLocalMatrix();
- }
+ nSetScaleY(mNativePtr, scaleY);
}
@SuppressWarnings("unused")
public float getTranslateX() {
- return mTranslateX;
+ return nGetTranslateX(mNativePtr);
}
@SuppressWarnings("unused")
public void setTranslateX(float translateX) {
- if (translateX != mTranslateX) {
- mTranslateX = translateX;
- updateLocalMatrix();
- }
+ nSetTranslateX(mNativePtr, translateX);
}
@SuppressWarnings("unused")
public float getTranslateY() {
- return mTranslateY;
+ return nGetTranslateY(mNativePtr);
}
@SuppressWarnings("unused")
public void setTranslateY(float translateY) {
- if (translateY != mTranslateY) {
- mTranslateY = translateY;
- updateLocalMatrix();
- }
+ nSetTranslateY(mNativePtr, translateY);
}
}
@@ -1362,6 +1148,7 @@
*/
private static abstract class VPath implements VObject {
protected PathParser.PathData mPathData = null;
+
String mPathName;
int mChangingConfigurations;
@@ -1379,10 +1166,6 @@
return mPathName;
}
- public boolean isClipPath() {
- return false;
- }
-
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
public PathParser.PathData getPathData() {
@@ -1393,79 +1176,7 @@
@SuppressWarnings("unused")
public void setPathData(PathParser.PathData pathData) {
mPathData.setPathData(pathData);
- }
-
- @Override
- public final void draw(Canvas canvas, TempState temp, Matrix groupStackedMatrix,
- ColorFilter filter, float scaleX, float scaleY) {
- final float matrixScale = VPath.getMatrixScale(groupStackedMatrix);
- if (matrixScale == 0) {
- // When either x or y is scaled to 0, we don't need to draw anything.
- return;
- }
-
- final Path path = temp.path;
- path.reset();
- toPath(temp, path);
-
- final Matrix pathMatrix = temp.pathMatrix;
- pathMatrix.set(groupStackedMatrix);
- pathMatrix.postScale(scaleX, scaleY);
-
- final Path renderPath = temp.renderPath;
- renderPath.reset();
- renderPath.addPath(path, pathMatrix);
-
- final float minScale = Math.min(scaleX, scaleY);
- final float strokeScale = minScale * matrixScale;
- drawPath(temp, renderPath, canvas, filter, strokeScale);
- }
-
- /**
- * Writes the path's nodes to an output Path for rendering.
- *
- * @param temp temporary state variables
- * @param outPath the output path
- */
- protected void toPath(TempState temp, Path outPath) {
- if (mPathData != null) {
- PathParser.createPathFromPathData(outPath, mPathData);
- }
- }
-
- /**
- * Draws the specified path into the supplied canvas.
- */
- protected abstract void drawPath(TempState temp, Path path, Canvas canvas,
- ColorFilter filter, float strokeScale);
-
- private static float getMatrixScale(Matrix groupStackedMatrix) {
- // Given unit vectors A = (0, 1) and B = (1, 0).
- // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
- // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
- // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
- // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
- //
- // For non-skew case, which is most of the cases, matrix scale is computing exactly the
- // scale on x and y axis, and take the minimal of these two.
- // For skew case, an unit square will mapped to a parallelogram. And this function will
- // return the minimal height of the 2 bases.
- float[] unitVectors = new float[] {0, 1, 1, 0};
- groupStackedMatrix.mapVectors(unitVectors);
- float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
- float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
- float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
- unitVectors[2], unitVectors[3]);
- float maxScale = MathUtils.max(scaleX, scaleY);
-
- float matrixScale = 0;
- if (maxScale > 0) {
- matrixScale = MathUtils.abs(crossProduct) / maxScale;
- }
- if (DBG_VECTOR_DRAWABLE) {
- Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
- }
- return matrixScale;
+ nSetPathData(getNativePtr(), mPathData.getNativePtr());
}
}
@@ -1473,21 +1184,31 @@
* Clip path, which only has name and pathData.
*/
private static class VClipPath extends VPath {
+ long mNativePtr = 0;
public VClipPath() {
+ mNativePtr = nCreateClipPath();
// Empty constructor.
}
public VClipPath(VClipPath copy) {
super(copy);
+ mNativePtr = nCreateClipPath(copy.mNativePtr);
}
@Override
- protected void drawPath(TempState temp, Path renderPath, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- canvas.clipPath(renderPath);
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ super.finalize();
+ }
+ @Override
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.VectorDrawableClipPath);
@@ -1522,95 +1243,54 @@
final String pathName = a.getString(R.styleable.VectorDrawableClipPath_name);
if (pathName != null) {
mPathName = pathName;
+ nSetName(mNativePtr, mPathName);
}
final String pathDataString = a.getString(R.styleable.VectorDrawableClipPath_pathData);
if (pathDataString != null) {
mPathData = new PathParser.PathData(pathDataString);
+ nSetPathString(mNativePtr, pathDataString, pathDataString.length());
}
}
-
- @Override
- public boolean isClipPath() {
- return true;
- }
}
/**
* Normal path, which contains all the fill / paint information.
*/
private static class VFullPath extends VPath {
+ private static final int STROKE_WIDTH_INDEX = 0;
+ private static final int STROKE_COLOR_INDEX = 1;
+ private static final int STROKE_ALPHA_INDEX = 2;
+ private static final int FILL_COLOR_INDEX = 3;
+ private static final int FILL_ALPHA_INDEX = 4;
+ private static final int TRIM_PATH_START_INDEX = 5;
+ private static final int TRIM_PATH_END_INDEX = 6;
+ private static final int TRIM_PATH_OFFSET_INDEX = 7;
+ private static final int STROKE_LINE_CAP_INDEX = 8;
+ private static final int STROKE_LINE_JOIN_INDEX = 9;
+ private static final int STROKE_MITER_LIMIT_INDEX = 10;
+ private static final int TOTAL_PROPERTY_COUNT = 11;
+
+ // Temp array to store property data obtained from native getter.
+ private byte[] mPropertyData;
/////////////////////////////////////////////////////
// Variables below need to be copied (deep copy if applicable) for mutation.
private int[] mThemeAttrs;
-
ColorStateList mStrokeColors = null;
- int mStrokeColor = Color.TRANSPARENT;
- float mStrokeWidth = 0;
-
ColorStateList mFillColors = null;
- int mFillColor = Color.TRANSPARENT;
- float mStrokeAlpha = 1.0f;
- int mFillRule;
- float mFillAlpha = 1.0f;
- float mTrimPathStart = 0;
- float mTrimPathEnd = 1;
- float mTrimPathOffset = 0;
-
- Paint.Cap mStrokeLineCap = Paint.Cap.BUTT;
- Paint.Join mStrokeLineJoin = Paint.Join.MITER;
- float mStrokeMiterlimit = 4;
+ private long mNativePtr = 0;
public VFullPath() {
// Empty constructor.
+ mNativePtr = nCreateFullPath();
}
public VFullPath(VFullPath copy) {
super(copy);
-
+ mNativePtr = nCreateFullPath(copy.mNativePtr);
mThemeAttrs = copy.mThemeAttrs;
-
mStrokeColors = copy.mStrokeColors;
- mStrokeColor = copy.mStrokeColor;
- mStrokeWidth = copy.mStrokeWidth;
- mStrokeAlpha = copy.mStrokeAlpha;
mFillColors = copy.mFillColors;
- mFillColor = copy.mFillColor;
- mFillRule = copy.mFillRule;
- mFillAlpha = copy.mFillAlpha;
- mTrimPathStart = copy.mTrimPathStart;
- mTrimPathEnd = copy.mTrimPathEnd;
- mTrimPathOffset = copy.mTrimPathOffset;
-
- mStrokeLineCap = copy.mStrokeLineCap;
- mStrokeLineJoin = copy.mStrokeLineJoin;
- mStrokeMiterlimit = copy.mStrokeMiterlimit;
- }
-
- private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
- switch (id) {
- case LINECAP_BUTT:
- return Paint.Cap.BUTT;
- case LINECAP_ROUND:
- return Paint.Cap.ROUND;
- case LINECAP_SQUARE:
- return Paint.Cap.SQUARE;
- default:
- return defValue;
- }
- }
-
- private Paint.Join getStrokeLineJoin(int id, Paint.Join defValue) {
- switch (id) {
- case LINEJOIN_MITER:
- return Paint.Join.MITER;
- case LINEJOIN_ROUND:
- return Paint.Join.ROUND;
- case LINEJOIN_BEVEL:
- return Paint.Join.BEVEL;
- default:
- return defValue;
- }
}
@Override
@@ -1618,17 +1298,22 @@
boolean changed = false;
if (mStrokeColors != null) {
- final int oldStrokeColor = mStrokeColor;
- mStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
- changed |= oldStrokeColor != mStrokeColor;
+ final int oldStrokeColor = getStrokeColor();
+ final int newStrokeColor = mStrokeColors.getColorForState(stateSet, oldStrokeColor);
+ changed |= oldStrokeColor != newStrokeColor;
+ if (oldStrokeColor != newStrokeColor) {
+ nSetStrokeColor(mNativePtr, newStrokeColor);
+ }
}
if (mFillColors != null) {
- final int oldFillColor = mFillColor;
- mFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
- changed |= oldFillColor != mFillColor;
+ final int oldFillColor = getFillColor();
+ final int newFillColor = mFillColors.getColorForState(stateSet, oldFillColor);
+ changed |= oldFillColor != newFillColor;
+ if (oldFillColor != newFillColor) {
+ nSetFillColor(mNativePtr, newFillColor);
+ }
}
-
return changed;
}
@@ -1638,101 +1323,8 @@
}
@Override
- public void toPath(TempState temp, Path path) {
- super.toPath(temp, path);
-
- if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
- VFullPath.applyTrim(temp, path, mTrimPathStart, mTrimPathEnd, mTrimPathOffset);
- }
- }
-
- @Override
- protected void drawPath(TempState temp, Path path, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- drawPathFill(temp, path, canvas, filter);
- drawPathStroke(temp, path, canvas, filter, strokeScale);
- }
-
- /**
- * Draws this path's fill, if necessary.
- */
- private void drawPathFill(TempState temp, Path path, Canvas canvas, ColorFilter filter) {
- if (mFillColor == Color.TRANSPARENT) {
- return;
- }
-
- if (temp.mFillPaint == null) {
- temp.mFillPaint = new Paint();
- temp.mFillPaint.setStyle(Paint.Style.FILL);
- temp.mFillPaint.setAntiAlias(true);
- }
-
- final Paint fillPaint = temp.mFillPaint;
- fillPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
- fillPaint.setColorFilter(filter);
- canvas.drawPath(path, fillPaint);
- }
-
- /**
- * Draws this path's stroke, if necessary.
- */
- private void drawPathStroke(TempState temp, Path path, Canvas canvas, ColorFilter filter,
- float strokeScale) {
- if (mStrokeColor == Color.TRANSPARENT) {
- return;
- }
-
- if (temp.mStrokePaint == null) {
- temp.mStrokePaint = new Paint();
- temp.mStrokePaint.setStyle(Paint.Style.STROKE);
- temp.mStrokePaint.setAntiAlias(true);
- }
-
- final Paint strokePaint = temp.mStrokePaint;
- if (mStrokeLineJoin != null) {
- strokePaint.setStrokeJoin(mStrokeLineJoin);
- }
-
- if (mStrokeLineCap != null) {
- strokePaint.setStrokeCap(mStrokeLineCap);
- }
-
- strokePaint.setStrokeMiter(mStrokeMiterlimit);
- strokePaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
- strokePaint.setColorFilter(filter);
- strokePaint.setStrokeWidth(mStrokeWidth * strokeScale);
- canvas.drawPath(path, strokePaint);
- }
-
- /**
- * Applies trimming to the specified path.
- */
- private static void applyTrim(TempState temp, Path path, float mTrimPathStart,
- float mTrimPathEnd, float mTrimPathOffset) {
- if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
- // No trimming necessary.
- return;
- }
-
- if (temp.mPathMeasure == null) {
- temp.mPathMeasure = new PathMeasure();
- }
- final PathMeasure pathMeasure = temp.mPathMeasure;
- pathMeasure.setPath(path, false);
-
- final float len = pathMeasure.getLength();
- final float start = len * ((mTrimPathStart + mTrimPathOffset) % 1.0f);
- final float end = len * ((mTrimPathEnd + mTrimPathOffset) % 1.0f);
- path.reset();
- if (start > end) {
- pathMeasure.getSegment(start, len, path, true);
- pathMeasure.getSegment(0, end, path, true);
- } else {
- pathMeasure.getSegment(start, end, path, true);
- }
-
- // Fix bug in measure.
- path.rLineTo(0, 0);
+ public long getNativePtr() {
+ return mNativePtr;
}
@Override
@@ -1743,7 +1335,44 @@
a.recycle();
}
+ @Override
+ protected void finalize() throws Throwable {
+ if (mNativePtr != 0) {
+ nDestroy(mNativePtr);
+ mNativePtr = 0;
+ }
+ super.finalize();
+ }
+
private void updateStateFromTypedArray(TypedArray a) {
+ int byteCount = TOTAL_PROPERTY_COUNT * 4;
+ if (mPropertyData == null) {
+ // Lazy initialization: If the path is created through copy constructor, this may
+ // never get called.
+ mPropertyData = new byte[byteCount];
+ }
+ // The bulk getters/setters of property data (e.g. stroke width, color, etc) allows us
+ // to pull current values from native and store modifications with only two methods,
+ // minimizing JNI overhead.
+ boolean success = nGetFullPathProperties(mNativePtr, mPropertyData, byteCount);
+ if (!success) {
+ throw new RuntimeException("Error: inconsistent property count");
+ }
+
+ ByteBuffer properties = ByteBuffer.wrap(mPropertyData);
+ properties.order(ByteOrder.nativeOrder());
+ float strokeWidth = properties.getFloat(STROKE_WIDTH_INDEX * 4);
+ int strokeColor = properties.getInt(STROKE_COLOR_INDEX * 4);
+ float strokeAlpha = properties.getFloat(STROKE_ALPHA_INDEX * 4);
+ int fillColor = properties.getInt(FILL_COLOR_INDEX * 4);
+ float fillAlpha = properties.getFloat(FILL_ALPHA_INDEX * 4);
+ float trimPathStart = properties.getFloat(TRIM_PATH_START_INDEX * 4);
+ float trimPathEnd = properties.getFloat(TRIM_PATH_END_INDEX * 4);
+ float trimPathOffset = properties.getFloat(TRIM_PATH_OFFSET_INDEX * 4);
+ int strokeLineCap = properties.getInt(STROKE_LINE_CAP_INDEX * 4);
+ int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
+ float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
+
// Account for any configuration changes.
mChangingConfigurations |= a.getChangingConfigurations();
@@ -1753,11 +1382,13 @@
final String pathName = a.getString(R.styleable.VectorDrawablePath_name);
if (pathName != null) {
mPathName = pathName;
+ nSetName(mNativePtr, mPathName);
}
final String pathString = a.getString(R.styleable.VectorDrawablePath_pathData);
if (pathString != null) {
mPathData = new PathParser.PathData(pathString);
+ nSetPathString(mNativePtr, pathString, pathString.length());
}
final ColorStateList fillColors = a.getColorStateList(
@@ -1766,7 +1397,7 @@
// If the color state list isn't stateful, discard the state
// list and keep the default (e.g. the only) color.
mFillColors = fillColors.isStateful() ? fillColors : null;
- mFillColor = fillColors.getDefaultColor();
+ fillColor = fillColors.getDefaultColor();
}
final ColorStateList strokeColors = a.getColorStateList(
@@ -1775,23 +1406,30 @@
// If the color state list isn't stateful, discard the state
// list and keep the default (e.g. the only) color.
mStrokeColors = strokeColors.isStateful() ? strokeColors : null;
- mStrokeColor = strokeColors.getDefaultColor();
+ strokeColor = strokeColors.getDefaultColor();
}
+ fillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, fillAlpha);
- mFillAlpha = a.getFloat(R.styleable.VectorDrawablePath_fillAlpha, mFillAlpha);
- mStrokeLineCap = getStrokeLineCap(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
- mStrokeLineJoin = getStrokeLineJoin(a.getInt(
- R.styleable.VectorDrawablePath_strokeLineJoin, -1), mStrokeLineJoin);
- mStrokeMiterlimit = a.getFloat(
- R.styleable.VectorDrawablePath_strokeMiterLimit, mStrokeMiterlimit);
- mStrokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha, mStrokeAlpha);
- mStrokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth, mStrokeWidth);
- mTrimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd, mTrimPathEnd);
- mTrimPathOffset = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathOffset, mTrimPathOffset);
- mTrimPathStart = a.getFloat(
- R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
+ strokeLineCap = a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineCap, strokeLineCap);
+ strokeLineJoin = a.getInt(
+ R.styleable.VectorDrawablePath_strokeLineJoin, strokeLineJoin);
+ strokeMiterLimit = a.getFloat(
+ R.styleable.VectorDrawablePath_strokeMiterLimit, strokeMiterLimit);
+ strokeAlpha = a.getFloat(R.styleable.VectorDrawablePath_strokeAlpha,
+ strokeAlpha);
+ strokeWidth = a.getFloat(R.styleable.VectorDrawablePath_strokeWidth,
+ strokeWidth);
+ trimPathEnd = a.getFloat(R.styleable.VectorDrawablePath_trimPathEnd,
+ trimPathEnd);
+ trimPathOffset = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathOffset, trimPathOffset);
+ trimPathStart = a.getFloat(
+ R.styleable.VectorDrawablePath_trimPathStart, trimPathStart);
+
+ nUpdateFullPathProperties(mNativePtr, strokeWidth, strokeColor, strokeAlpha,
+ fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset,
+ strokeMiterLimit, strokeLineCap, strokeLineJoin);
}
@Override
@@ -1813,104 +1451,169 @@
/* Setters and Getters, used by animator from AnimatedVectorDrawable. */
@SuppressWarnings("unused")
int getStrokeColor() {
- return mStrokeColor;
+ return nGetStrokeColor(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeColor(int strokeColor) {
mStrokeColors = null;
- mStrokeColor = strokeColor;
+ nSetStrokeColor(mNativePtr, strokeColor);
}
@SuppressWarnings("unused")
float getStrokeWidth() {
- return mStrokeWidth;
+ return nGetStrokeWidth(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeWidth(float strokeWidth) {
- mStrokeWidth = strokeWidth;
+ nSetStrokeWidth(mNativePtr, strokeWidth);
}
@SuppressWarnings("unused")
float getStrokeAlpha() {
- return mStrokeAlpha;
+ return nGetStrokeAlpha(mNativePtr);
}
@SuppressWarnings("unused")
void setStrokeAlpha(float strokeAlpha) {
- mStrokeAlpha = strokeAlpha;
+ nSetStrokeAlpha(mNativePtr, strokeAlpha);
}
@SuppressWarnings("unused")
int getFillColor() {
- return mFillColor;
+ return nGetFillColor(mNativePtr);
}
@SuppressWarnings("unused")
void setFillColor(int fillColor) {
mFillColors = null;
- mFillColor = fillColor;
+ nSetFillColor(mNativePtr, fillColor);
}
@SuppressWarnings("unused")
float getFillAlpha() {
- return mFillAlpha;
+ return nGetFillAlpha(mNativePtr);
}
@SuppressWarnings("unused")
void setFillAlpha(float fillAlpha) {
- mFillAlpha = fillAlpha;
+ nSetFillAlpha(mNativePtr, fillAlpha);
}
@SuppressWarnings("unused")
float getTrimPathStart() {
- return mTrimPathStart;
+ return nGetTrimPathStart(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathStart(float trimPathStart) {
- mTrimPathStart = trimPathStart;
+ nSetTrimPathStart(mNativePtr, trimPathStart);
}
@SuppressWarnings("unused")
float getTrimPathEnd() {
- return mTrimPathEnd;
+ return nGetTrimPathEnd(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathEnd(float trimPathEnd) {
- mTrimPathEnd = trimPathEnd;
+ nSetTrimPathEnd(mNativePtr, trimPathEnd);
}
@SuppressWarnings("unused")
float getTrimPathOffset() {
- return mTrimPathOffset;
+ return nGetTrimPathOffset(mNativePtr);
}
@SuppressWarnings("unused")
void setTrimPathOffset(float trimPathOffset) {
- mTrimPathOffset = trimPathOffset;
+ nSetTrimPathOffset(mNativePtr, trimPathOffset);
}
}
- static class TempState {
- final Matrix pathMatrix = new Matrix();
- final Path path = new Path();
- final Path renderPath = new Path();
-
- PathMeasure mPathMeasure;
- Paint mFillPaint;
- Paint mStrokePaint;
- }
-
interface VObject {
- void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
- ColorFilter filter, float scaleX, float scaleY);
+ long getNativePtr();
void inflate(Resources r, AttributeSet attrs, Theme theme);
boolean canApplyTheme();
void applyTheme(Theme t);
boolean onStateChange(int[] state);
boolean isStateful();
}
+
+ private static native long nCreateRenderer(long rootGroupPtr);
+ private static native void nDestroyRenderer(long rendererPtr);
+ private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+ float viewportHeight);
+ private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
+ private static native float nGetRootAlpha(long rendererPtr);
+ private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
+
+ private static native void nDraw(long rendererPtr, long canvasWrapperPtr,
+ long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
+ private static native long nCreateFullPath();
+ private static native long nCreateFullPath(long mNativeFullPathPtr);
+ private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
+ int length);
+
+ private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
+ int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
+ int strokeLineJoin);
+
+ private static native long nCreateClipPath();
+ private static native long nCreateClipPath(long clipPathPtr);
+
+ private static native long nCreateGroup();
+ private static native long nCreateGroup(long groupPtr);
+ private static native void nDestroy(long nodePtr);
+ private static native void nSetName(long nodePtr, String name);
+ private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
+ int length);
+ private static native void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+ float pivotY, float scaleX, float scaleY, float translateX, float translateY);
+
+ private static native void nAddChild(long groupPtr, long nodePtr);
+ private static native void nSetPathString(long pathPtr, String pathString, int length);
+
+ /**
+ * The setters and getters below for paths and groups are here temporarily, and will be
+ * removed once the animation in AVD is replaced with RenderNodeAnimator, in which case the
+ * animation will modify these properties in native. By then no JNI hopping would be necessary
+ * for VD during animation, and these setters and getters will be obsolete.
+ */
+ // Setters and getters during animation.
+ private static native float nGetRotation(long groupPtr);
+ private static native void nSetRotation(long groupPtr, float rotation);
+ private static native float nGetPivotX(long groupPtr);
+ private static native void nSetPivotX(long groupPtr, float pivotX);
+ private static native float nGetPivotY(long groupPtr);
+ private static native void nSetPivotY(long groupPtr, float pivotY);
+ private static native float nGetScaleX(long groupPtr);
+ private static native void nSetScaleX(long groupPtr, float scaleX);
+ private static native float nGetScaleY(long groupPtr);
+ private static native void nSetScaleY(long groupPtr, float scaleY);
+ private static native float nGetTranslateX(long groupPtr);
+ private static native void nSetTranslateX(long groupPtr, float translateX);
+ private static native float nGetTranslateY(long groupPtr);
+ private static native void nSetTranslateY(long groupPtr, float translateY);
+
+ // Setters and getters for VPath during animation.
+ private static native void nSetPathData(long pathPtr, long pathDataPtr);
+ private static native float nGetStrokeWidth(long pathPtr);
+ private static native void nSetStrokeWidth(long pathPtr, float width);
+ private static native int nGetStrokeColor(long pathPtr);
+ private static native void nSetStrokeColor(long pathPtr, int strokeColor);
+ private static native float nGetStrokeAlpha(long pathPtr);
+ private static native void nSetStrokeAlpha(long pathPtr, float alpha);
+ private static native int nGetFillColor(long pathPtr);
+ private static native void nSetFillColor(long pathPtr, int fillColor);
+ private static native float nGetFillAlpha(long pathPtr);
+ private static native void nSetFillAlpha(long pathPtr, float fillAlpha);
+ private static native float nGetTrimPathStart(long pathPtr);
+ private static native void nSetTrimPathStart(long pathPtr, float trimPathStart);
+ private static native float nGetTrimPathEnd(long pathPtr);
+ private static native void nSetTrimPathEnd(long pathPtr, float trimPathEnd);
+ private static native float nGetTrimPathOffset(long pathPtr);
+ private static native void nSetTrimPathOffset(long pathPtr, float trimPathOffset);
}
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 3d4e47d..914ac3d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -100,16 +100,17 @@
* then on success, *cookie is set to the value corresponding to the
* newly-added asset source.
*/
- bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
+ bool addAssetPath(const String8& path, int32_t* cookie,
+ bool appAsLib=false, bool isSystemAsset=false);
bool addOverlayPath(const String8& path, int32_t* cookie);
- /*
+ /*
* Convenience for adding the standard system assets. Uses the
* ANDROID_ROOT environment variable to find them.
*/
bool addDefaultAssets();
- /*
+ /*
* Iterate over the asset paths in this manager. (Previously
* added via addAssetPath() and addDefaultAssets().) On first call,
* 'cookie' must be 0, resulting in the first cookie being returned.
@@ -118,7 +119,7 @@
*/
int32_t nextAssetPath(const int32_t cookie) const;
- /*
+ /*
* Return an asset path in the manager. 'which' must be between 0 and
* countAssetPaths().
*/
@@ -221,11 +222,11 @@
* the current data.
*/
bool isUpToDate();
-
+
/**
* Get the known locales for this asset manager object.
*/
- void getLocales(Vector<String8>* locales) const;
+ void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
/**
* Generate idmap data to translate resources IDs between a package and a
@@ -237,11 +238,13 @@
private:
struct asset_path
{
- asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
+ asset_path() : path(""), type(kFileTypeRegular), idmap(""),
+ isSystemOverlay(false), isSystemAsset(false) {}
String8 path;
FileType type;
String8 idmap;
bool isSystemOverlay;
+ bool isSystemAsset;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 49b6333..428a2b8 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1552,9 +1552,9 @@
status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
- bool appAsLib=false);
+ bool appAsLib=false, bool isSystemAsset=false);
- status_t add(ResTable* src);
+ status_t add(ResTable* src, bool isSystemAsset=false);
status_t addEmpty(const int32_t cookie);
status_t getError() const;
@@ -1822,9 +1822,9 @@
// Return the configurations (ResTable_config) that we know about
void getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap=false,
- bool ignoreAndroidPackage=false) const;
+ bool ignoreAndroidPackage=false, bool includeSystemConfigs=true) const;
- void getLocales(Vector<String8>* locales) const;
+ void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
// Generate an idmap.
//
@@ -1860,7 +1860,7 @@
typedef Vector<Type*> TypeList;
status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
- bool appAsLib, const int32_t cookie, bool copyData);
+ bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
ssize_t getResourcePackageIndex(uint32_t resID) const;
@@ -1873,10 +1873,11 @@
size_t nameLen, uint32_t* outTypeSpecFlags) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header, bool appAsLib);
+ const ResTable_package* const pkg, const Header* const header,
+ bool appAsLib, bool isSystemAsset);
void print_value(const Package* pkg, const Res_value& value) const;
-
+
mutable Mutex mLock;
status_t mError;
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 40fb0d3..7adad8a 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -350,7 +350,7 @@
/**
* Returns the {@code PrivateKey} for the requested alias, or null
- * if no there is no result.
+ * if there is no result.
*
* <p> This method may block while waiting for a connection to another process, and must never
* be called from the main thread.
@@ -371,7 +371,7 @@
final IKeyChainService keyChainService = keyChainConnection.getService();
final String keyId = keyChainService.requestPrivateKey(alias);
if (keyId == null) {
- throw new KeyChainException("keystore had a problem");
+ return null;
}
return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 8a03b94..6913f43a 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,8 @@
delete[] mVendor;
}
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
+bool AssetManager::addAssetPath(
+ const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
{
AutoMutex _l(mLock);
@@ -222,6 +223,7 @@
}
delete manifestAsset;
+ ap.isSystemAsset = isSystemAsset;
mAssetPaths.add(ap);
// new paths are always added at the end
@@ -233,6 +235,7 @@
// Load overlays, if any
asset_path oap;
for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+ oap.isSystemAsset = isSystemAsset;
mAssetPaths.add(oap);
}
#endif
@@ -340,7 +343,7 @@
String8 path(root);
path.appendPath(kSystemAssets);
- return addAssetPath(path, NULL);
+ return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
}
int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -682,10 +685,10 @@
ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
if (sharedRes != NULL) {
ALOGV("Copying existing resources for %s", ap.path.string());
- mResources->add(sharedRes);
+ mResources->add(sharedRes, ap.isSystemAsset);
} else {
ALOGV("Parsing resources for %s", ap.path.string());
- mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
+ mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
}
onlyEmptyResources = false;
@@ -831,11 +834,11 @@
return mZipSet.isUpToDate();
}
-void AssetManager::getLocales(Vector<String8>* locales) const
+void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
ResTable* res = mResources;
if (res != NULL) {
- res->getLocales(locales);
+ res->getLocales(locales, includeSystemLocales);
}
const size_t numLocales = locales->size();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 21b543e..44f92c7 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,16 @@
// table that defined the package); the ones after are skins on top of it.
struct ResTable::PackageGroup
{
- PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
+ PackageGroup(
+ ResTable* _owner, const String16& _name, uint32_t _id,
+ bool appAsLib, bool _isSystemAsset)
: owner(_owner)
, name(_name)
, id(_id)
, largestTypeId(0)
, bags(NULL)
, dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+ , isSystemAsset(_isSystemAsset)
{ }
~PackageGroup() {
@@ -3178,6 +3181,10 @@
// by having these tables in a per-package scope rather than
// per-package-group.
DynamicRefTable dynamicRefTable;
+
+ // If the package group comes from a system asset. Used in
+ // determining non-system locales.
+ const bool isSystemAsset;
};
struct ResTable::bag_set
@@ -3572,8 +3579,9 @@
copyData);
}
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
- bool appAsLib) {
+status_t ResTable::add(
+ Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+ bool appAsLib, bool isSystemAsset) {
const void* data = asset->getBuffer(true);
if (data == NULL) {
ALOGW("Unable to get buffer of resource asset file");
@@ -3592,20 +3600,21 @@
}
return addInternal(data, static_cast<size_t>(asset->getLength()),
- idmapData, idmapSize, appAsLib, cookie, copyData);
+ idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
}
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
{
mError = src->mError;
- for (size_t i=0; i<src->mHeaders.size(); i++) {
+ for (size_t i=0; i < src->mHeaders.size(); i++) {
mHeaders.add(src->mHeaders[i]);
}
- for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+ for (size_t i=0; i < src->mPackageGroups.size(); i++) {
PackageGroup* srcPg = src->mPackageGroups[i];
- PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
+ PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+ false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
for (size_t j=0; j<srcPg->packages.size(); j++) {
pg->packages.add(srcPg->packages[j]);
}
@@ -3646,7 +3655,7 @@
}
status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
- bool appAsLib, const int32_t cookie, bool copyData)
+ bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
{
if (!data) {
return NO_ERROR;
@@ -3749,7 +3758,8 @@
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
+ if (parsePackage(
+ (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -5663,7 +5673,7 @@
}
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
- bool ignoreAndroidPackage) const {
+ bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size();
String16 android("android");
for (size_t i = 0; i < packageCount; i++) {
@@ -5671,6 +5681,9 @@
if (ignoreAndroidPackage && android == packageGroup->name) {
continue;
}
+ if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+ continue;
+ }
const size_t typeCount = packageGroup->types.size();
for (size_t j = 0; j < typeCount; j++) {
const TypeList& typeList = packageGroup->types[j];
@@ -5707,11 +5720,14 @@
}
}
-void ResTable::getLocales(Vector<String8>* locales) const
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{
Vector<ResTable_config> configs;
ALOGV("calling getConfigurations");
- getConfigurations(&configs);
+ getConfigurations(&configs,
+ false /* ignoreMipmap */,
+ false /* ignoreAndroidPackage */,
+ includeSystemLocales /* includeSystemConfigs */);
ALOGV("called getConfigurations size=%d", (int)configs.size());
const size_t I = configs.size();
@@ -5937,7 +5953,7 @@
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header, bool appAsLib)
+ const Header* const header, bool appAsLib, bool isSystemAsset)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5985,8 +6001,8 @@
if (id >= 256) {
LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
- } else if (id == 0 || appAsLib) {
- // This is a library so assign an ID
+ } else if (id == 0 || appAsLib || isSystemAsset) {
+ // This is a library or a system asset, so assign an ID
id = mNextPackageId++;
}
@@ -6018,7 +6034,7 @@
char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
- group = new PackageGroup(this, String16(tmpName), id, appAsLib);
+ group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
if (group == NULL) {
delete package;
return (mError=NO_MEMORY);
diff --git a/libs/common_time/common_time_server.cpp b/libs/common_time/common_time_server.cpp
index 01372e0..f72ffaa 100644
--- a/libs/common_time/common_time_server.cpp
+++ b/libs/common_time/common_time_server.cpp
@@ -143,7 +143,7 @@
// Create the eventfd we will use to signal our thread to wake up when
// needed.
- mWakeupThreadFD = eventfd(0, EFD_NONBLOCK);
+ mWakeupThreadFD = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
// seed the random number generator (used to generated timeline IDs)
srand48(static_cast<unsigned int>(systemTime()));
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0d1ee46..11056d4 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -86,7 +86,7 @@
TextDropShadowCache.cpp \
Texture.cpp \
TextureCache.cpp \
- VectorDrawablePath.cpp \
+ VectorDrawable.cpp \
protos/hwui.proto
hwui_test_common_src_files := \
@@ -108,6 +108,7 @@
hwui_src_files += \
BakedOpDispatcher.cpp \
BakedOpRenderer.cpp \
+ BakedOpState.cpp \
OpReorderer.cpp \
RecordingCanvas.cpp
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index d4dbb00..097675a 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -79,7 +79,9 @@
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+ renderer.renderGlop(nullptr, clip, glop);
}
void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
@@ -183,7 +185,9 @@
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+ renderer.renderGlop(nullptr, clip, glop);
}
static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
@@ -224,7 +228,7 @@
};
static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
- const Rect* renderClip, TextRenderType renderType) {
+ const ClipBase* renderClip, TextRenderType renderType) {
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) {
@@ -272,7 +276,7 @@
bool forceFinish = (renderType == TextRenderType::Flush);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
- const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr;
+ const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
fontRenderer.renderPosText(op.paint, localOpClip,
(const char*) op.glyphs, op.glyphCount, x, y,
op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
@@ -287,7 +291,8 @@
void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
const MergedBakedOpList& opList) {
- const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr;
+ ClipRect renderTargetClip(opList.clip);
+ const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -297,26 +302,6 @@
}
}
-void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
-void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) {
- LOG_ALWAYS_FATAL("unsupported operation");
-}
-
namespace VertexBufferRenderFlags {
enum {
Offset = 0x1,
@@ -414,7 +399,7 @@
.setMeshTexturedUnitQuad(texture->uvMapper)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+ .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
.build();
renderer.renderGlop(state, glop);
}
@@ -518,6 +503,10 @@
renderer.renderGlop(state, glop);
}
+void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
+ renderer.renderFunctor(op, state);
+}
+
void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
@@ -697,8 +686,51 @@
}
void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
- const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr;
- renderTextOp(renderer, op, state, clip, TextRenderType::Flush);
+ renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
+}
+
+void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
+ // Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
+ // TODO: respect clipSideFlags, once we record with bounds
+ auto renderTargetClip = state.computedState.clipState;
+
+ FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
+ fontRenderer.setFont(op.paint, SkMatrix::I());
+ fontRenderer.setTextureFiltering(true);
+
+ Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
+
+ int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
+ SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(op.paint);
+ TextDrawFunctor functor(&renderer, &state, renderTargetClip,
+ 0.0f, 0.0f, false, alpha, mode, op.paint);
+
+ bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
+ const Rect localSpaceClip = state.computedState.computeLocalSpaceClip();
+ if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip,
+ reinterpret_cast<const char*>(op.glyphs), op.glyphCount,
+ op.path, op.hOffset, op.vOffset,
+ mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
+ if (mustDirtyRenderTarget) {
+ // manually dirty render target, since TextDrawFunctor won't
+ state.computedState.transform.mapRect(layerBounds);
+ renderer.dirtyRenderTarget(layerBounds);
+ }
+ }
+}
+
+void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
+ const bool tryToSnap = !op.layer->getForceFilter();
+ float alpha = (op.layer->getAlpha() / 255.0f) * state.alpha;
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+ .setFillTextureLayer(*(op.layer), alpha)
+ .setTransform(state.computedState.transform, TransformFlags::None)
+ .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(op.layer->getWidth(), op.layer->getHeight()))
+ .build();
+ renderer.renderGlop(state, glop);
}
void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index ed34ada..4dfdd3f 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -36,13 +36,13 @@
// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
#define X(Type) \
static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
- MAP_MERGED_OPS(X)
+ MAP_MERGEABLE_OPS(X)
#undef X
// Declares all "onBitmapOp(...)" style methods for every op type
#define X(Type) \
static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
- MAP_OPS(X)
+ MAP_RENDERABLE_OPS(X)
#undef X
};
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 93a9406..a0d5fae 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -60,27 +60,67 @@
}
void BakedOpRenderer::endLayer() {
+ if (mRenderTarget.stencil) {
+ // if stencil was used for clipping, detach it and return it to pool
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "glfbrb endlayer failed");
+ mCaches.renderBufferCache.put(mRenderTarget.stencil);
+ mRenderTarget.stencil = nullptr;
+ }
+ mRenderTarget.lastStencilClip = nullptr;
+
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
- mRenderTarget.offscreenBuffer = nullptr;
+ mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
// Detach the texture from the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
- mRenderTarget.frameBufferId = -1;
+ mRenderTarget.frameBufferId = 0;
}
void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
+ LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
mRenderState.bindFramebuffer(0);
setViewport(width, height);
- mCaches.clearGarbage();
if (!mOpaque) {
clearColorBuffer(repaintRect);
}
+
+ mRenderState.debugOverdraw(true, true);
}
-void BakedOpRenderer::endFrame() {
+void BakedOpRenderer::endFrame(const Rect& repaintRect) {
+ if (CC_UNLIKELY(Properties::debugOverdraw)) {
+ ClipRect overdrawClip(repaintRect);
+ Rect viewportRect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight);
+ // overdraw visualization
+ for (int i = 1; i <= 4; i++) {
+ if (i < 4) {
+ // nth level of overdraw tests for n+1 draws per pixel
+ mRenderState.stencil().enableDebugTest(i + 1, false);
+ } else {
+ // 4th level tests for 4 or higher draws per pixel
+ mRenderState.stencil().enableDebugTest(4, true);
+ }
+
+ SkPaint paint;
+ paint.setColor(mCaches.getOverdrawColor(i));
+ Glop glop;
+ GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshUnitQuad()
+ .setFillPaint(paint, 1.0f)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewMapUnitToRect(viewportRect)
+ .build();
+ renderGlop(nullptr, &overdrawClip, glop);
+ }
+ mRenderState.stencil().disable();
+ }
+
+ mCaches.clearGarbage();
mCaches.pathCache.trim();
mCaches.tessellationCache.trim();
@@ -128,22 +168,153 @@
return texture;
}
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop) {
+// clears and re-fills stencil with provided rendertarget space quads,
+// and then put stencil into test mode
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
+ int incrementThreshold) {
+ mRenderState.stencil().enableWrite(incrementThreshold);
+ mRenderState.stencil().clear();
+ Glop glop;
+ GlopBuilder(mRenderState, mCaches, &glop)
+ .setRoundRectClipState(nullptr)
+ .setMeshIndexedQuads(quadVertices.data(), quadVertices.size() / 4)
+ .setFillBlack()
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewIdentityEmptyBounds()
+ .build();
+ mRenderState.render(glop, mRenderTarget.orthoMatrix);
+ mRenderState.stencil().enableTest(incrementThreshold);
+}
+
+void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
+ auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+ int quadCount = rectList.getTransformedRectanglesCount();
+ std::vector<Vertex> rectangleVertices;
+ rectangleVertices.reserve(quadCount * 4);
+ for (int i = 0; i < quadCount; i++) {
+ const TransformedRectangle& tr(rectList.getTransformedRectangle(i));
+ const Matrix4& transform = tr.getTransform();
+ Rect bounds = tr.getBounds();
+ if (transform.rectToRect()) {
+ // If rectToRect, can simply map bounds before storing verts
+ transform.mapRect(bounds);
+ bounds.doIntersect(clip->rect);
+ if (bounds.isEmpty()) {
+ continue; // will be outside of scissor, skip
+ }
+ }
+
+ rectangleVertices.push_back(Vertex{bounds.left, bounds.top});
+ rectangleVertices.push_back(Vertex{bounds.right, bounds.top});
+ rectangleVertices.push_back(Vertex{bounds.left, bounds.bottom});
+ rectangleVertices.push_back(Vertex{bounds.right, bounds.bottom});
+
+ if (!transform.rectToRect()) {
+ // If not rectToRect, must map each point individually
+ for (auto cur = rectangleVertices.end() - 4; cur < rectangleVertices.end(); cur++) {
+ transform.mapPoint(cur->x, cur->y);
+ }
+ }
+ }
+ setupStencilQuads(rectangleVertices, rectList.getTransformedRectanglesCount());
+}
+
+void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) {
+ auto&& region = reinterpret_cast<const ClipRegion*>(clip)->region;
+
+ std::vector<Vertex> regionVertices;
+ SkRegion::Cliperator it(region, clip->rect.toSkIRect());
+ while (!it.done()) {
+ const SkIRect& r = it.rect();
+ regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fTop});
+ regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fTop});
+ regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fBottom});
+ regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fBottom});
+ it.next();
+ }
+ setupStencilQuads(regionVertices, 0);
+}
+
+void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) {
+ // prepare scissor / stencil
mRenderState.scissor().setEnabled(clip != nullptr);
if (clip) {
- mRenderState.scissor().set(clip->left, mRenderTarget.viewportHeight - clip->bottom,
- clip->getWidth(), clip->getHeight());
+ mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
}
+
+ if (CC_LIKELY(!Properties::debugOverdraw)) {
+ // only modify stencil mode and content when it's not used for overdraw visualization
+ if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
+ // NOTE: this pointer check is only safe for non-rect clips,
+ // since rect clips may be created on the stack
+ if (mRenderTarget.lastStencilClip != clip) {
+ // Stencil needed, but current stencil isn't up to date
+ mRenderTarget.lastStencilClip = clip;
+
+ if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
+ OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
+ mRenderTarget.stencil = mCaches.renderBufferCache.get(
+ Stencil::getLayerStencilFormat(),
+ layer->texture.width, layer->texture.height);
+ // stencil is bound + allocated - associate it with current FBO
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+ }
+
+ if (clip->mode == ClipMode::RectangleList) {
+ setupStencilRectList(clip);
+ } else {
+ setupStencilRegion(clip);
+ }
+ } else {
+ // stencil is up to date - just need to ensure it's enabled (since an unclipped
+ // or scissor-only clipped op may have been drawn, disabling the stencil)
+ int incrementThreshold = 0;
+ if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+ auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+ incrementThreshold = rectList.getTransformedRectanglesCount();
+ }
+ mRenderState.stencil().enableTest(incrementThreshold);
+ }
+ } else {
+ // either scissor or no clip, so disable stencil test
+ mRenderState.stencil().disable();
+ }
+ }
+
+ // dirty offscreenbuffer
if (dirtyBounds && mRenderTarget.offscreenBuffer) {
// register layer damage to draw-back region
android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
dirtyBounds->right, dirtyBounds->bottom);
mRenderTarget.offscreenBuffer->region.orSelf(dirty);
}
+}
+
+void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+ const Glop& glop) {
+ prepareRender(dirtyBounds, clip);
mRenderState.render(glop, mRenderTarget.orthoMatrix);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
+void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& state) {
+ prepareRender(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded());
+
+ DrawGlInfo info;
+ auto&& clip = state.computedState.clipRect();
+ info.clipLeft = clip.left;
+ info.clipTop = clip.top;
+ info.clipRight = clip.right;
+ info.clipBottom = clip.bottom;
+ info.isLayer = offscreenRenderTarget();
+ info.width = mRenderTarget.viewportWidth;
+ info.height = mRenderTarget.viewportHeight;
+ state.computedState.transform.copyTo(&info.transform[0]);
+
+ mRenderState.invokeFunctor(op.functor, DrawGlInfo::kModeDraw, &info);
+}
+
void BakedOpRenderer::dirtyRenderTarget(const Rect& uiDirty) {
if (mRenderTarget.offscreenBuffer) {
android::Rect dirty(uiDirty.left, uiDirty.top, uiDirty.right, uiDirty.bottom);
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index d7600db..65e8b29 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -27,6 +27,7 @@
struct Glop;
class Layer;
class RenderState;
+struct ClipBase;
/**
* Main rendering manager for a collection of work - one frame + any contained FBOs.
@@ -59,28 +60,32 @@
Caches& caches() { return mCaches; }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
- void endFrame();
+ void endFrame(const Rect& repaintRect);
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
void endLayer();
Texture* getTexture(const SkBitmap* bitmap);
- const LightInfo& getLightInfo() { return mLightInfo; }
+ const LightInfo& getLightInfo() const { return mLightInfo; }
void renderGlop(const BakedOpState& state, const Glop& glop) {
- bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
renderGlop(&state.computedState.clippedBounds,
- useScissor ? &state.computedState.clipRect : nullptr,
+ state.computedState.getClipIfNeeded(),
glop);
}
+ void renderFunctor(const FunctorOp& op, const BakedOpState& state);
- void renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop);
+ void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
void dirtyRenderTarget(const Rect& dirtyRect);
- bool didDraw() { return mHasDrawn; }
+ bool didDraw() const { return mHasDrawn; }
private:
void setViewport(uint32_t width, uint32_t height);
void clearColorBuffer(const Rect& clearRect);
+ void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
+ void setupStencilRectList(const ClipBase* clip);
+ void setupStencilRegion(const ClipBase* clip);
+ void setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold);
RenderState& mRenderState;
Caches& mCaches;
@@ -90,10 +95,23 @@
// render target state - setup by start/end layer/frame
// only valid to use in between start/end pairs.
struct {
+ // If not drawing to a layer: fbo = 0, offscreenBuffer = null,
+ // Otherwise these refer to currently painting layer's state
GLuint frameBufferId = 0;
OffscreenBuffer* offscreenBuffer = nullptr;
+
+ // Used when drawing to a layer and using stencil clipping. otherwise null.
+ RenderBuffer* stencil = nullptr;
+
+ // value representing the ClipRectList* or ClipRegion* currently stored in
+ // the stencil of the current render target
+ const ClipBase* lastStencilClip = nullptr;
+
+ // Size of renderable region in current render target - for layers, may not match actual
+ // bounds of FBO texture. offscreenBuffer->texture has this information.
uint32_t viewportWidth = 0;
uint32_t viewportHeight = 0;
+
Matrix4 orthoMatrix;
} mRenderTarget;
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
new file mode 100644
index 0000000..e6b943a
--- /dev/null
+++ b/libs/hwui/BakedOpState.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BakedOpState.h"
+
+#include "ClipArea.h"
+
+namespace android {
+namespace uirenderer {
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke) {
+ // resolvedMatrix = parentMatrix * localMatrix
+ transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+
+ // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+ clippedBounds = recordedOp.unmappedBounds;
+ if (CC_UNLIKELY(expandForStroke)) {
+ // account for non-hairline stroke
+ clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+ }
+ transform.mapRect(clippedBounds);
+ if (CC_UNLIKELY(expandForStroke
+ && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+ // account for hairline stroke when stroke may be < 1 scaled pixel
+ // Non translate || strokeWidth < 1 is conservative, but will cover all cases
+ clippedBounds.outset(0.5f);
+ }
+
+ // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+ clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+ recordedOp.localClip, *(snapshot.transform));
+ LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
+
+ const Rect& clipRect = clipState->rect;
+ if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) {
+ // Rejected based on either empty clip, or bounds not intersecting with clip
+ if (clipState) {
+ allocator.rewindIfLastAlloc(clipState);
+ clipState = nullptr;
+ }
+ clippedBounds.setEmpty();
+ } else {
+ // Not rejected! compute true clippedBounds and clipSideFlags
+ if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
+ if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
+ if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
+ if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+ clippedBounds.doIntersect(clipRect);
+ }
+}
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
+ transform = *snapshot.transform;
+
+ // Since the op doesn't have known bounds, we conservatively set the mapped bounds
+ // to the current clipRect, and clipSideFlags to Full.
+ clipState = snapshot.mutateClipArea().serializeClip(allocator);
+ LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
+ clippedBounds = clipState->rect;
+ transform.mapRect(clippedBounds);
+ clipSideFlags = OpClipSideFlags::Full;
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 9c836a0..9df4e3a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -52,80 +52,35 @@
*/
class ResolvedRenderState {
public:
- // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
- ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) {
- /* TODO: benchmark a fast path for translate-only matrices, such as:
- if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
- && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
- float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
- float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
- transform.loadTranslate(translateX, translateY, 0);
+ ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke);
- // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipRect = recordedOp.localClipRect;
- clipRect.translate(translateX, translateY);
- clipRect.doIntersect(snapshot.getClipRect());
- clipRect.snapToPixelBoundaries();
+ // Constructor for unbounded ops without transform/clip (namely shadows)
+ ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
- // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
- clippedBounds = recordedOp.unmappedBounds;
- clippedBounds.translate(translateX, translateY);
- } ... */
+ Rect computeLocalSpaceClip() const {
+ Matrix4 inverse;
+ inverse.loadInverse(transform);
- // resolvedMatrix = parentMatrix * localMatrix
- transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
-
- // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipRect = recordedOp.localClipRect;
- snapshot.transform->mapRect(clipRect);
- clipRect.doIntersect(snapshot.getRenderTargetClip());
- clipRect.snapToPixelBoundaries();
-
- // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
- clippedBounds = recordedOp.unmappedBounds;
- if (CC_UNLIKELY(expandForStroke)) {
- // account for non-hairline stroke
- clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
- }
- transform.mapRect(clippedBounds);
- if (CC_UNLIKELY(expandForStroke
- && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
- // account for hairline stroke when stroke may be < 1 scaled pixel
- // Non translate || strokeWidth < 1 is conservative, but will cover all cases
- clippedBounds.outset(0.5f);
- }
-
- if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
- if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
- if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
- if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
- clippedBounds.doIntersect(clipRect);
-
- /**
- * TODO: once we support complex clips, we may want to reject to avoid that work where
- * possible. Should we:
- * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
- * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
- * and early return null in one place.
- */
- }
-
- /**
- * Constructor for unbounded ops without transform/clip (namely shadows)
- *
- * Since the op doesn't have known bounds, we conservatively set the mapped bounds
- * to the current clipRect, and clipSideFlags to Full.
- */
- ResolvedRenderState(const Snapshot& snapshot) {
- transform = *snapshot.transform;
- clipRect = snapshot.getRenderTargetClip();
- clippedBounds = clipRect;
- transform.mapRect(clippedBounds);
- clipSideFlags = OpClipSideFlags::Full;
+ Rect outClip(clipRect());
+ inverse.mapRect(outClip);
+ return outClip;
}
Matrix4 transform;
- Rect clipRect;
+ const Rect& clipRect() const {
+ return clipState->rect;
+ }
+ bool requiresClip() const {
+ return clipSideFlags != OpClipSideFlags::None
+ || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+ }
+
+ // returns the clip if it's needed to draw the operation, otherwise nullptr
+ const ClipBase* getClipIfNeeded() const {
+ return requiresClip() ? clipState : nullptr;
+ }
+ const ClipBase* clipState = nullptr;
int clipSideFlags = 0;
Rect clippedBounds;
};
@@ -138,8 +93,9 @@
class BakedOpState {
public:
static BakedOpState* tryConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const RecordedOp& recordedOp) {
- BakedOpState* bakedState = new (allocator) BakedOpState(snapshot, recordedOp, false);
+ Snapshot& snapshot, const RecordedOp& recordedOp) {
+ BakedOpState* bakedState = new (allocator) BakedOpState(
+ allocator, snapshot, recordedOp, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -156,13 +112,13 @@
};
static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+ Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
: true;
BakedOpState* bakedState = new (allocator) BakedOpState(
- snapshot, recordedOp, expandForStroke);
+ allocator, snapshot, recordedOp, expandForStroke);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -172,11 +128,11 @@
}
static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
- const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+ Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
// clip isn't empty, so construct the op
- return new (allocator) BakedOpState(snapshot, shadowOpPtr);
+ return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
}
static void* operator new(size_t size, LinearAllocator& allocator) {
@@ -193,15 +149,16 @@
const RecordedOp* op;
private:
- BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke)
- : computedState(snapshot, recordedOp, expandForStroke)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp, bool expandForStroke)
+ : computedState(allocator, snapshot, recordedOp, expandForStroke)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
, projectionPathMask(snapshot.projectionPathMask)
, op(&recordedOp) {}
- BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
- : computedState(snapshot)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
+ : computedState(allocator, snapshot)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
, projectionPathMask(snapshot.projectionPathMask)
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 6a6cc42..cf2726b5 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -45,6 +45,21 @@
}
}
+void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
+ if (mWidth != viewportWidth || mHeight != viewportHeight) {
+ mWidth = viewportWidth;
+ mHeight = viewportHeight;
+ mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
+ mCanvas.onViewportInitialized();
+ }
+
+ freeAllSnapshots();
+ mSnapshot = allocSnapshot(&mFirstSnapshot,
+ SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ mSnapshot->setRelativeLightCenter(Vector3());
+ mSaveCount = 1;
+}
+
void CanvasState::initializeSaveStack(
int viewportWidth, int viewportHeight,
float clipLeft, float clipTop,
@@ -192,7 +207,7 @@
///////////////////////////////////////////////////////////////////////////////
bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
- mSnapshot->clip(left, top, right, bottom, op);
+ mSnapshot->clip(Rect(left, top, right, bottom), op);
mDirtyClip = true;
return !mSnapshot->clipIsEmpty();
}
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 4709ef4..b9e87ae 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -80,6 +80,12 @@
* Initializes the first snapshot, computing the projection matrix,
* and stores the dimensions of the render target.
*/
+ void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
+
+ /**
+ * Initializes the first snapshot, computing the projection matrix,
+ * and stores the dimensions of the render target.
+ */
void initializeSaveStack(int viewportWidth, int viewportHeight,
float clipLeft, float clipTop, float clipRight, float clipBottom,
const Vector3& lightCenter);
@@ -168,6 +174,7 @@
void freeAllSnapshots();
/// indicates that the clip has been changed since the last time it was consumed
+ // TODO: delete when switching to HWUI_NEW_OPS
bool mDirtyClip;
/// Dimensions of the drawing surface
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index fd6f0b5..160090d 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -15,10 +15,11 @@
*/
#include "ClipArea.h"
+#include "utils/LinearAllocator.h"
+
#include <SkPath.h>
#include <limits>
-
-#include "Rect.h"
+#include <type_traits>
namespace android {
namespace uirenderer {
@@ -171,12 +172,18 @@
return rectangleListAsRegion;
}
+void RectangleList::transform(const Matrix4& transform) {
+ for (int index = 0; index < mTransformedRectanglesCount; index++) {
+ mTransformedRectangles[index].transform(transform);
+ }
+}
+
/*
* ClipArea
*/
ClipArea::ClipArea()
- : mMode(Mode::Rectangle) {
+ : mMode(ClipMode::Rectangle) {
}
/*
@@ -184,45 +191,44 @@
*/
void ClipArea::setViewportDimensions(int width, int height) {
+ mPostViewportClipObserved = false;
mViewportBounds.set(0, 0, width, height);
mClipRect = mViewportBounds;
}
void ClipArea::setEmpty() {
- mMode = Mode::Rectangle;
+ onClipUpdated();
+ mMode = ClipMode::Rectangle;
mClipRect.setEmpty();
mClipRegion.setEmpty();
mRectangleList.setEmpty();
}
void ClipArea::setClip(float left, float top, float right, float bottom) {
- mMode = Mode::Rectangle;
+ onClipUpdated();
+ mMode = ClipMode::Rectangle;
mClipRect.set(left, top, right, bottom);
mClipRegion.setEmpty();
}
-void ClipArea::clipRectWithTransform(float left, float top, float right,
- float bottom, const mat4* transform, SkRegion::Op op) {
- Rect r(left, top, right, bottom);
- clipRectWithTransform(r, transform, op);
-}
-
void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op) {
+ onClipUpdated();
switch (mMode) {
- case Mode::Rectangle:
+ case ClipMode::Rectangle:
rectangleModeClipRectWithTransform(r, transform, op);
break;
- case Mode::RectangleList:
+ case ClipMode::RectangleList:
rectangleListModeClipRectWithTransform(r, transform, op);
break;
- case Mode::Region:
+ case ClipMode::Region:
regionModeClipRectWithTransform(r, transform, op);
break;
}
}
void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+ onClipUpdated();
enterRegionMode();
mClipRegion.op(region, op);
onClipRegionUpdated();
@@ -230,6 +236,7 @@
void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
SkRegion::Op op) {
+ onClipUpdated();
SkMatrix skTransform;
transform->copyTo(skTransform);
SkPath transformed;
@@ -247,7 +254,7 @@
// Entering rectangle mode discards any
// existing clipping information from the other modes.
// The only way this occurs is by a clip setting operation.
- mMode = Mode::Rectangle;
+ mMode = ClipMode::Rectangle;
}
void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
@@ -274,13 +281,6 @@
rectangleListModeClipRectWithTransform(r, transform, op);
}
-void ClipArea::rectangleModeClipRectWithTransform(float left, float top,
- float right, float bottom, const mat4* transform, SkRegion::Op op) {
- Rect r(left, top, right, bottom);
- rectangleModeClipRectWithTransform(r, transform, op);
- mClipRect = mRectangleList.calculateBounds();
-}
-
/*
* RectangleList mode implementation
*/
@@ -289,8 +289,8 @@
// Is is only legal to enter rectangle list mode from
// rectangle mode, since rectangle list mode cannot represent
// all clip areas that can be represented by a region.
- ALOG_ASSERT(mMode == Mode::Rectangle);
- mMode = Mode::RectangleList;
+ ALOG_ASSERT(mMode == ClipMode::Rectangle);
+ mMode = ClipMode::RectangleList;
mRectangleList.set(mClipRect, Matrix4::identity());
}
@@ -303,23 +303,16 @@
}
}
-void ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
- float right, float bottom, const mat4* transform, SkRegion::Op op) {
- Rect r(left, top, right, bottom);
- rectangleListModeClipRectWithTransform(r, transform, op);
-}
-
/*
* Region mode implementation
*/
void ClipArea::enterRegionMode() {
- Mode oldMode = mMode;
- mMode = Mode::Region;
- if (oldMode != Mode::Region) {
- if (oldMode == Mode::Rectangle) {
- mClipRegion.setRect(mClipRect.left, mClipRect.top,
- mClipRect.right, mClipRect.bottom);
+ ClipMode oldMode = mMode;
+ mMode = ClipMode::Region;
+ if (oldMode != ClipMode::Region) {
+ if (oldMode == ClipMode::Rectangle) {
+ mClipRegion.setRect(mClipRect.toSkIRect());
} else {
mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
onClipRegionUpdated();
@@ -336,11 +329,6 @@
onClipRegionUpdated();
}
-void ClipArea::regionModeClipRectWithTransform(float left, float top,
- float right, float bottom, const mat4* transform, SkRegion::Op op) {
- regionModeClipRectWithTransform(Rect(left, top, right, bottom), transform, op);
-}
-
void ClipArea::onClipRegionUpdated() {
if (!mClipRegion.isEmpty()) {
mClipRect.set(mClipRegion.getBounds());
@@ -354,5 +342,172 @@
}
}
+/**
+ * Clip serialization
+ */
+
+const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
+ if (!mPostViewportClipObserved) {
+ // Only initial clip-to-viewport observed, so no serialization of clip necessary
+ return nullptr;
+ }
+
+ static_assert(std::is_trivially_destructible<Rect>::value,
+ "expect Rect to be trivially destructible");
+ static_assert(std::is_trivially_destructible<RectangleList>::value,
+ "expect RectangleList to be trivially destructible");
+
+ if (mLastSerialization == nullptr) {
+ switch (mMode) {
+ case ClipMode::Rectangle:
+ mLastSerialization = allocator.create<ClipRect>(mClipRect);
+ break;
+ case ClipMode::RectangleList:
+ mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+ break;
+ case ClipMode::Region:
+ mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+ break;
+ }
+ }
+ return mLastSerialization;
+}
+
+inline static const Rect& getRect(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRect*>(scb)->rect;
+}
+
+inline static const RectangleList& getRectList(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRectList*>(scb)->rectList;
+}
+
+inline static const SkRegion& getRegion(const ClipBase* scb) {
+ return reinterpret_cast<const ClipRegion*>(scb)->region;
+}
+
+// Conservative check for too many rectangles to fit in rectangle list.
+// For simplicity, doesn't account for rect merging
+static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
+ int currentRectCount = clipArea.isRectangleList()
+ ? clipArea.getRectangleList().getTransformedRectanglesCount()
+ : 1;
+ int recordedRectCount = (scb->mode == ClipMode::RectangleList)
+ ? getRectList(scb).getTransformedRectanglesCount()
+ : 1;
+ return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
+}
+
+const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
+ const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+ // if no recordedClip passed, just serialize current state
+ if (!recordedClip) return serializeClip(allocator);
+
+ if (!mLastResolutionResult
+ || recordedClip != mLastResolutionClip
+ || recordedClipTransform != mLastResolutionTransform) {
+ mLastResolutionClip = recordedClip;
+ mLastResolutionTransform = recordedClipTransform;
+
+ if (CC_LIKELY(mMode == ClipMode::Rectangle
+ && recordedClip->mode == ClipMode::Rectangle
+ && recordedClipTransform.rectToRect())) {
+ // common case - result is a single rectangle
+ auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+ recordedClipTransform.mapRect(rectClip->rect);
+ rectClip->rect.doIntersect(mClipRect);
+ mLastResolutionResult = rectClip;
+ } else if (CC_UNLIKELY(mMode == ClipMode::Region
+ || recordedClip->mode == ClipMode::Region
+ || cannotFitInRectangleList(*this, recordedClip))) {
+ // region case
+ SkRegion other;
+ switch (recordedClip->mode) {
+ case ClipMode::Rectangle:
+ if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+ // simple transform, skip creating SkPath
+ Rect resultClip(getRect(recordedClip));
+ recordedClipTransform.mapRect(resultClip);
+ other.setRect(resultClip.toSkIRect());
+ } else {
+ SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+ recordedClipTransform);
+ other.setPath(transformedRect, createViewportRegion());
+ }
+ break;
+ case ClipMode::RectangleList: {
+ RectangleList transformedList(getRectList(recordedClip));
+ transformedList.transform(recordedClipTransform);
+ other = transformedList.convertToRegion(createViewportRegion());
+ break;
+ }
+ case ClipMode::Region:
+ other = getRegion(recordedClip);
+
+ // TODO: handle non-translate transforms properly!
+ other.translate(recordedClipTransform.getTranslateX(),
+ recordedClipTransform.getTranslateY());
+ }
+
+ ClipRegion* regionClip = allocator.create<ClipRegion>();
+ switch (mMode) {
+ case ClipMode::Rectangle:
+ regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::RectangleList:
+ regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+ other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::Region:
+ regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+ break;
+ }
+ regionClip->rect.set(regionClip->region.getBounds());
+ mLastResolutionResult = regionClip;
+ } else {
+ auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
+ auto&& rectList = rectListClip->rectList;
+ if (mMode == ClipMode::Rectangle) {
+ rectList.set(mClipRect, Matrix4::identity());
+ }
+
+ if (recordedClip->mode == ClipMode::Rectangle) {
+ rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+ } else {
+ const RectangleList& other = getRectList(recordedClip);
+ for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
+ auto&& tr = other.getTransformedRectangle(i);
+ Matrix4 totalTransform(recordedClipTransform);
+ totalTransform.multiply(tr.getTransform());
+ rectList.intersectWith(tr.getBounds(), totalTransform);
+ }
+ }
+ rectListClip->rect = rectList.calculateBounds();
+ mLastResolutionResult = rectListClip;
+ }
+ }
+ return mLastResolutionResult;
+}
+
+void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
+ if (!clip) return; // nothing to do
+
+ if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
+ clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+ } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+ auto&& rectList = getRectList(clip);
+ for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
+ auto&& tr = rectList.getTransformedRectangle(i);
+ Matrix4 totalTransform(transform);
+ totalTransform.multiply(tr.getTransform());
+ clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
+ }
+ } else {
+ SkRegion region(getRegion(clip));
+ // TODO: handle non-translate transforms properly!
+ region.translate(transform.getTranslateX(), transform.getTranslateY());
+ clipRegion(region, SkRegion::kIntersect_Op);
+ }
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index f88fd92..479796d 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -16,15 +16,17 @@
#ifndef CLIPAREA_H
#define CLIPAREA_H
-#include <SkRegion.h>
-
#include "Matrix.h"
#include "Rect.h"
#include "utils/Pair.h"
+#include <SkRegion.h>
+
namespace android {
namespace uirenderer {
+class LinearAllocator;
+
Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
class TransformedRectangle {
@@ -50,6 +52,12 @@
return mTransform;
}
+ void transform(const Matrix4& transform) {
+ Matrix4 t;
+ t.loadMultiply(transform, mTransform);
+ mTransform = t;
+ }
+
private:
Rect mBounds;
Matrix4 mTransform;
@@ -66,27 +74,62 @@
void setEmpty();
void set(const Rect& bounds, const Matrix4& transform);
bool intersectWith(const Rect& bounds, const Matrix4& transform);
+ void transform(const Matrix4& transform);
SkRegion convertToRegion(const SkRegion& clip) const;
Rect calculateBounds() const;
-private:
enum {
kMaxTransformedRectangles = 5
};
+private:
int mTransformedRectanglesCount;
TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
};
-class ClipArea {
-private:
- enum class Mode {
- Rectangle,
- Region,
- RectangleList
- };
+enum class ClipMode {
+ Rectangle,
+ RectangleList,
+ // region and path - intersected. if either is empty, don't use
+ Region
+};
+
+struct ClipBase {
+ ClipBase(ClipMode mode)
+ : mode(mode) {}
+ ClipBase(const Rect& rect)
+ : mode(ClipMode::Rectangle)
+ , rect(rect) {}
+ const ClipMode mode;
+ // Bounds of the clipping area, used to define the scissor, and define which
+ // portion of the stencil is updated/used
+ Rect rect;
+};
+
+struct ClipRect : ClipBase {
+ ClipRect(const Rect& rect)
+ : ClipBase(rect) {}
+};
+
+struct ClipRectList : ClipBase {
+ ClipRectList(const RectangleList& rectList)
+ : ClipBase(ClipMode::RectangleList)
+ , rectList(rectList) {}
+ RectangleList rectList;
+};
+
+struct ClipRegion : ClipBase {
+ ClipRegion(const SkRegion& region)
+ : ClipBase(ClipMode::Region)
+ , region(region) {}
+ ClipRegion()
+ : ClipBase(ClipMode::Region) {}
+ SkRegion region;
+};
+
+class ClipArea {
public:
ClipArea();
@@ -98,8 +141,6 @@
void setEmpty();
void setClip(float left, float top, float right, float bottom);
- void clipRectWithTransform(float left, float top, float right, float bottom,
- const mat4* transform, SkRegion::Op op);
void clipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
void clipRegion(const SkRegion& region, SkRegion::Op op);
@@ -119,26 +160,27 @@
}
bool isRegion() const {
- return Mode::Region == mMode;
+ return ClipMode::Region == mMode;
}
bool isSimple() const {
- return mMode == Mode::Rectangle;
+ return mMode == ClipMode::Rectangle;
}
bool isRectangleList() const {
- return mMode == Mode::RectangleList;
+ return mMode == ClipMode::RectangleList;
}
+ const ClipBase* serializeClip(LinearAllocator& allocator);
+ const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
+ const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+
private:
void enterRectangleMode();
void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
- void rectangleModeClipRectWithTransform(float left, float top, float right,
- float bottom, const mat4* transform, SkRegion::Op op);
void enterRectangleListMode();
- void rectangleListModeClipRectWithTransform(float left, float top,
- float right, float bottom, const mat4* transform, SkRegion::Op op);
void rectangleListModeClipRectWithTransform(const Rect& r,
const mat4* transform, SkRegion::Op op);
@@ -147,12 +189,17 @@
void enterRegionMode();
void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
SkRegion::Op op);
- void regionModeClipRectWithTransform(float left, float top, float right,
- float bottom, const mat4* transform, SkRegion::Op op);
void ensureClipRegion();
void onClipRegionUpdated();
+ // Called by every state modifying public method.
+ void onClipUpdated() {
+ mPostViewportClipObserved = true;
+ mLastSerialization = nullptr;
+ mLastResolutionResult = nullptr;
+ }
+
SkRegion createViewportRegion() {
return SkRegion(mViewportBounds.toSkIRect());
}
@@ -163,7 +210,22 @@
pathAsRegion.setPath(path, createViewportRegion());
}
- Mode mMode;
+ ClipMode mMode;
+ bool mPostViewportClipObserved = false;
+
+ /**
+ * If mLastSerialization is non-null, it represents an already serialized copy
+ * of the current clip state. If null, it has not been computed.
+ */
+ const ClipBase* mLastSerialization = nullptr;
+
+ /**
+ * This pair of pointers is a single entry cache of most recently seen
+ */
+ const ClipBase* mLastResolutionResult = nullptr;
+ const ClipBase* mLastResolutionClip = nullptr;
+ Matrix4 mLastResolutionTransform;
+
Rect mViewportBounds;
Rect mClipRect;
SkRegion mClipRegion;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 7038334..f833a54 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -53,8 +53,7 @@
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
-bool DeferredLayerUpdater::apply() {
- bool success = true;
+void DeferredLayerUpdater::apply() {
// These properties are applied the same to both layer types
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
@@ -73,7 +72,6 @@
setTransform(nullptr);
}
}
- return success;
}
void DeferredLayerUpdater::doUpdateTexImage() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index df7c594..6a3c890 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -77,13 +77,13 @@
ANDROID_API void setPaint(const SkPaint* paint);
- ANDROID_API bool apply();
+ void apply();
Layer* backingLayer() {
return mLayer;
}
- ANDROID_API void detachSurfaceTexture();
+ void detachSurfaceTexture();
private:
// Generic properties
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 8acdb62..ed31a2c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -83,7 +83,7 @@
.setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
.setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, renderer->currentSnapshot()->alpha)
.setTransform(*(renderer->currentSnapshot()), transformFlags)
- .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+ .setModelViewOffsetRect(0, 0, Rect())
.build();
renderer->renderGlop(glop);
#endif
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index ff4dc4a..9994498 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -47,6 +47,7 @@
#if HWUI_NEW_OPS
class BakedOpState;
class BakedOpRenderer;
+struct ClipBase;
#else
class OpenGLRenderer;
#endif
@@ -57,7 +58,7 @@
#if HWUI_NEW_OPS
BakedOpRenderer* renderer,
const BakedOpState* bakedState,
- const Rect* clip,
+ const ClipBase* clip,
#else
OpenGLRenderer* renderer,
#endif
@@ -81,7 +82,7 @@
#if HWUI_NEW_OPS
BakedOpRenderer* renderer;
const BakedOpState* bakedState;
- const Rect* clip;
+ const ClipBase* clip;
#else
OpenGLRenderer* renderer;
#endif
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index bcf819e..e72f396 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@
// Canvas transform isn't applied to the mesh at draw time,
//since it's already built in.
- MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
+ MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
};
};
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index f3ac93b..45fc16c 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -78,7 +78,7 @@
mOutGlop->mesh.vertices = {
vbo,
VertexAttribFlags::TextureCoord,
- nullptr, nullptr, nullptr,
+ nullptr, (const void*) kMeshTextureOffset, nullptr,
kTextureVertexStride };
mOutGlop->mesh.elementCount = elementCount;
return *this;
@@ -101,7 +101,7 @@
GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
if (uvMapper) {
// can't use unit quad VBO, so build UV vertices manually
- return setMeshTexturedUvQuad(uvMapper, Rect(0, 0, 1, 1));
+ return setMeshTexturedUvQuad(uvMapper, Rect(1, 1));
}
TRIGGER_STAGE(kMeshStage);
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index eb9b55f..c305f65 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -243,6 +243,7 @@
dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
(float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
+ dprintf(fd, "\n50th percentile: %ums", findPercentile(data, 50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(data, 90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(data, 95));
dprintf(fd, "\n99th percentile: %ums", findPercentile(data, 99));
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index e9e5d81..0cf643f 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -287,7 +287,7 @@
}
void LayerRenderer::updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform) {
+ bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform) {
if (layer) {
layer->setBlend(!isOpaque);
layer->setForceFilter(forceFilter);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index e4a54b0..38c3705 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -59,7 +59,7 @@
static Layer* createRenderLayer(RenderState& renderState, uint32_t width, uint32_t height);
static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
- bool isOpaque, bool forceFilter, GLenum renderTarget, float* textureTransform);
+ bool isOpaque, bool forceFilter, GLenum renderTarget, const float* textureTransform);
static void destroyLayer(Layer* layer);
static bool copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index c017638..1c25f26 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -139,9 +139,11 @@
}
void multiply(const Matrix4& v) {
- Matrix4 u;
- u.loadMultiply(*this, v);
- *this = u;
+ if (!v.isIdentity()) {
+ Matrix4 u;
+ u.loadMultiply(*this, v);
+ *this = u;
+ }
}
void multiply(float v);
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index ec03e83..3f492d5 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -90,7 +90,8 @@
}
MergingOpBatch(batchid_t batchId, BakedOpState* op)
- : BatchBase(batchId, op, true) {
+ : BatchBase(batchId, op, true)
+ , mClipSideFlags(op->computedState.clipSideFlags) {
}
/*
@@ -192,22 +193,17 @@
mBounds.unionWith(op->computedState.clippedBounds);
mOps.push_back(op);
- const int newClipSideFlags = op->computedState.clipSideFlags;
- mClipSideFlags |= newClipSideFlags;
-
- const Rect& opClip = op->computedState.clipRect;
- if (newClipSideFlags & OpClipSideFlags::Left) mClipRect.left = opClip.left;
- if (newClipSideFlags & OpClipSideFlags::Top) mClipRect.top = opClip.top;
- if (newClipSideFlags & OpClipSideFlags::Right) mClipRect.right = opClip.right;
- if (newClipSideFlags & OpClipSideFlags::Bottom) mClipRect.bottom = opClip.bottom;
+ // Because a new op must have passed canMergeWith(), we know it's passed the clipping compat
+ // check, and doesn't extend past a side of the clip that's in use by the merged batch.
+ // Therefore it's safe to simply always merge flags, and use the bounds as the clip rect.
+ mClipSideFlags |= op->computedState.clipSideFlags;
}
- bool getClipSideFlags() const { return mClipSideFlags; }
- const Rect& getClipRect() const { return mClipRect; }
+ int getClipSideFlags() const { return mClipSideFlags; }
+ const Rect& getClipRect() const { return mBounds; }
private:
- int mClipSideFlags = 0;
- Rect mClipRect;
+ int mClipSideFlags;
};
OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height,
@@ -308,12 +304,6 @@
mergingBatch->getClipSideFlags(),
mergingBatch->getClipRect()
};
- if (data.clipSideFlags) {
- // if right or bottom sides aren't used to clip, init them to viewport bounds
- // in the clip rect, so it can be used to scissor
- if (!(data.clipSideFlags & OpClipSideFlags::Right)) data.clip.right = width;
- if (!(data.clipSideFlags & OpClipSideFlags::Bottom)) data.clip.bottom = height;
- }
mergedReceivers[opId](arg, data);
} else {
for (const BakedOpState* op : batch->getOps()) {
@@ -470,7 +460,7 @@
deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
saveLayerBounds,
Matrix4::identity(),
- saveLayerBounds,
+ nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
deferEndLayerOp(*new (mAllocator) EndLayerOp());
@@ -614,7 +604,7 @@
mCanvasState.getLocalClipBounds(),
mCanvasState.currentSnapshot()->getRelativeLightCenter());
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
- mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
+ mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
if (CC_LIKELY(bakedOpState)) {
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
}
@@ -662,9 +652,7 @@
[](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); },
void OpReorderer::deferNodeOps(const RenderNode& renderNode) {
typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op);
- static OpDispatcher receivers[] = {
- MAP_OPS(OP_RECEIVER)
- };
+ static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
const DisplayList& displayList = *(renderNode.getDisplayList());
@@ -691,10 +679,10 @@
if (op.renderNode->nothingToDraw()) return;
int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
- // apply state from RecordedOp
+ // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
+ mCanvasState.writableSnapshot()->mutateClipArea().applyClip(op.localClip,
+ *mCanvasState.currentSnapshot()->transform);
mCanvasState.concatMatrix(op.localMatrix);
- mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
- op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
// then apply state from node properties, and defer ops
deferNodePropsAndOps(*op.renderNode);
@@ -716,7 +704,7 @@
BakedOpState::StrokeBehavior strokeBehavior) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
- mAllocator, *mCanvasState.currentSnapshot(), op, strokeBehavior);
+ mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
}
@@ -779,11 +767,17 @@
const OvalOp* resolvedOp = new (mAllocator) OvalOp(
unmappedBounds,
op.localMatrix,
- op.localClipRect,
+ op.localClip,
op.paint);
deferOvalOp(*resolvedOp);
}
+void OpReorderer::deferFunctorOp(const FunctorOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
+}
+
void OpReorderer::deferLinesOp(const LinesOp& op) {
batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
deferStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
@@ -833,7 +827,7 @@
const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
op.localMatrix,
- op.localClipRect,
+ op.localClip,
op.paint, *op.rx, *op.ry);
deferRoundRectOp(*resolvedOp);
}
@@ -844,14 +838,16 @@
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
}
+static batchid_t textBatchId(const SkPaint& paint) {
+ // TODO: better handling of shader (since we won't care about color then)
+ return paint.getColor() == SK_ColorBLACK ? OpBatchType::Text : OpBatchType::ColorText;
+}
+
void OpReorderer::deferTextOp(const TextOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
if (!bakedState) return; // quick rejected
- // TODO: better handling of shader (since we won't care about color then)
- batchid_t batchId = op.paint->getColor() == SK_ColorBLACK
- ? OpBatchType::Text : OpBatchType::ColorText;
-
+ batchid_t batchId = textBatchId(*(op.paint));
if (bakedState->computedState.transform.isPureTranslate()
&& PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
@@ -861,6 +857,18 @@
}
}
+void OpReorderer::deferTextOnPathOp(const TextOnPathOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
+}
+
+void OpReorderer::deferTextureLayerOp(const TextureLayerOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
+}
+
void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
float contentTranslateX, float contentTranslateY,
const Rect& repaintRect,
@@ -943,7 +951,7 @@
LayerOp* drawLayerOp = new (mAllocator) LayerOp(
beginLayerOp.unmappedBounds,
beginLayerOp.localMatrix,
- beginLayerOp.localClipRect,
+ beginLayerOp.localClip,
beginLayerOp.paint,
&mLayerReorderers[finishedLayerIndex].offscreenBuffer);
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
@@ -958,13 +966,5 @@
}
}
-void OpReorderer::deferLayerOp(const LayerOp& op) {
- LOG_ALWAYS_FATAL("unsupported");
-}
-
-void OpReorderer::deferShadowOp(const ShadowOp& op) {
- LOG_ALWAYS_FATAL("unsupported");
-}
-
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 35343c8b..429913f 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -43,7 +43,6 @@
namespace OpBatchType {
enum {
- None = 0, // Don't batch
Bitmap,
MergedPatch,
AlphaVertices,
@@ -52,6 +51,8 @@
Text,
ColorText,
Shadow,
+ TextureLayer,
+ Functor,
Count // must be last
};
@@ -137,7 +138,7 @@
template <typename StaticDispatcher, typename Renderer>
void replayBakedOps(Renderer& renderer) {
/**
- * defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
+ * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
* dispatch the op via a method on a static dispatcher when the op is replayed.
*
* For example a BitmapOp would resolve, via the lambda lookup, to calling:
@@ -148,29 +149,19 @@
[](void* renderer, const BakedOpState& state) { \
StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), static_cast<const Type&>(*(state.op)), state); \
},
- static BakedOpReceiver unmergedReceivers[] = {
- MAP_OPS(X)
- };
+ static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
#undef X
/**
- * defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
- * static dispatcher when the group of merged ops is replayed. Unmergeable ops trigger
- * a LOG_ALWAYS_FATAL().
+ * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
+ * static dispatcher when the group of merged ops is replayed.
*/
#define X(Type) \
[](void* renderer, const MergedBakedOpList& opList) { \
- LOG_ALWAYS_FATAL("op type %d does not support merging", opList.states[0]->op->opId); \
- },
- #define Y(Type) \
- [](void* renderer, const MergedBakedOpList& opList) { \
StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
},
- static MergedOpReceiver mergedReceivers[] = {
- MAP_OPS_BASED_ON_MERGEABILITY(X, Y)
- };
+ static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
#undef X
- #undef Y
// Relay through layers in reverse order, since layers
// later in the list will be drawn by earlier ones
@@ -191,7 +182,7 @@
const LayerReorderer& fbo0 = mLayerReorderers[0];
renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
- renderer.endFrame();
+ renderer.endFrame(fbo0.repaintRect);
}
void dump() const {
@@ -222,7 +213,7 @@
LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
- return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
+ return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
}
// should always be surrounded by a save/restore pair, and not called if DisplayList is null
@@ -255,9 +246,9 @@
* These private methods are called from within deferImpl to defer each individual op
* type differently.
*/
-#define INTERNAL_OP_HANDLER(Type) \
- void defer##Type(const Type& op);
- MAP_OPS(INTERNAL_OP_HANDLER)
+#define X(Type) void defer##Type(const Type& op);
+ MAP_DEFERRABLE_OPS(X)
+#undef X
std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index f49237c..92b758d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1474,7 +1474,7 @@
.setMeshTexturedMesh(vertices, bitmapCount * 6)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
- .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
+ .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(bounds.getWidth(), bounds.getHeight()))
.build();
renderGlop(glop, GlopRenderType::Multi);
}
@@ -1497,7 +1497,7 @@
.setMeshTexturedUnitQuad(texture->uvMapper)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
- .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+ .setModelViewMapUnitToRectSnap(Rect(texture->width, texture->height))
.build();
renderGlop(glop);
}
@@ -1642,7 +1642,7 @@
.setMeshPatchQuads(*mesh)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), TransformFlags::None)
- .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
+ .setModelViewOffsetRectSnap(left, top, Rect(right - left, bottom - top)) // TODO: get minimal bounds from patch
.build();
renderGlop(glop);
}
@@ -1672,7 +1672,7 @@
.setMeshTexturedIndexedQuads(vertices, elementCount)
.setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
.setTransform(*currentSnapshot(), transformFlags)
- .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+ .setModelViewOffsetRect(0, 0, Rect())
.build();
renderGlop(glop, GlopRenderType::Multi);
}
@@ -2268,7 +2268,7 @@
.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
.setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
.setTransform(*currentSnapshot(), TransformFlags::None)
- .setModelViewOffsetRectSnap(0, 0, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+ .setModelViewOffsetRectSnap(0, 0, Rect(layer->layer.getWidth(), layer->layer.getHeight()))
.build();
DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
#if DEBUG_LAYERS_AS_REGIONS
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 4c87b18..c4bbb74 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HWUI_PATHPARSER_H
#define ANDROID_HWUI_PATHPARSER_H
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include "utils/VectorDrawableUtils.h"
#include <jni.h>
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0669596..083aeb7 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -53,6 +53,8 @@
ProfileType Properties::sProfileType = ProfileType::None;
bool Properties::sDisableProfileBars = false;
+bool Properties::waitForGpuCompletion = false;
+
static int property_get_int(const char* key, int defaultValue) {
char buf[PROPERTY_VALUE_MAX] = {'\0',};
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 1dde7e0..88f1dbc 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -285,6 +285,9 @@
static ProfileType getProfileType();
+ // Should be used only by test apps
+ static bool waitForGpuCompletion;
+
private:
static ProfileType sProfileType;
static bool sDisableProfileBars;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index d1a4866..b243f99 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -33,65 +33,96 @@
namespace android {
namespace uirenderer {
+struct ClipBase;
class OffscreenBuffer;
class RenderNode;
struct Vertex;
/**
- * On of the provided macros is executed for each op type in order. The first will be used for ops
- * that cannot merge, and the second for those that can.
+ * Authoritative op list, used for generating the op ID enum, ID based LUTS, and
+ * the functions to which they dispatch. Parameter macros are executed for each op,
+ * in order, based on the op's type.
*
- * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs.
+ * There are 4 types of op:
+ *
+ * Pre render - not directly consumed by renderer, reorder stage resolves this into renderable type
+ * Render only - generated renderable ops - never passed to a reorderer
+ * Unmergeable - reorderable, renderable (but not mergeable)
+ * Mergeable - reorderable, renderable (and mergeable)
*/
-#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \
- U_OP_FN(ArcOp) \
- M_OP_FN(BitmapOp) \
- U_OP_FN(BitmapMeshOp) \
- U_OP_FN(BitmapRectOp) \
- U_OP_FN(CirclePropsOp) \
- U_OP_FN(LinesOp) \
- U_OP_FN(OvalOp) \
- M_OP_FN(PatchOp) \
- U_OP_FN(PathOp) \
- U_OP_FN(PointsOp) \
- U_OP_FN(RectOp) \
- U_OP_FN(RenderNodeOp) \
- U_OP_FN(RoundRectOp) \
- U_OP_FN(RoundRectPropsOp) \
- U_OP_FN(ShadowOp) \
- U_OP_FN(SimpleRectsOp) \
- M_OP_FN(TextOp) \
- U_OP_FN(BeginLayerOp) \
- U_OP_FN(EndLayerOp) \
- U_OP_FN(LayerOp)
+#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
+ PRE_RENDER_OP_FN(RenderNodeOp) \
+ PRE_RENDER_OP_FN(CirclePropsOp) \
+ PRE_RENDER_OP_FN(RoundRectPropsOp) \
+ PRE_RENDER_OP_FN(BeginLayerOp) \
+ PRE_RENDER_OP_FN(EndLayerOp) \
+ \
+ RENDER_ONLY_OP_FN(ShadowOp) \
+ RENDER_ONLY_OP_FN(LayerOp) \
+ \
+ UNMERGEABLE_OP_FN(ArcOp) \
+ UNMERGEABLE_OP_FN(BitmapMeshOp) \
+ UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(FunctorOp) \
+ UNMERGEABLE_OP_FN(LinesOp) \
+ UNMERGEABLE_OP_FN(OvalOp) \
+ UNMERGEABLE_OP_FN(PathOp) \
+ UNMERGEABLE_OP_FN(PointsOp) \
+ UNMERGEABLE_OP_FN(RectOp) \
+ UNMERGEABLE_OP_FN(RoundRectOp) \
+ UNMERGEABLE_OP_FN(SimpleRectsOp) \
+ UNMERGEABLE_OP_FN(TextOnPathOp) \
+ UNMERGEABLE_OP_FN(TextureLayerOp) \
+ \
+ MERGEABLE_OP_FN(BitmapOp) \
+ MERGEABLE_OP_FN(PatchOp) \
+ MERGEABLE_OP_FN(TextOp)
/**
- * The provided macro is executed for each op type in order. This is used in cases where
- * merge-ability of ops doesn't matter.
+ * LUT generators, which will insert nullptr for unsupported ops
*/
-#define MAP_OPS(OP_FN) \
- MAP_OPS_BASED_ON_MERGEABILITY(OP_FN, OP_FN)
+#define NULLPTR_OP_FN(Type) nullptr,
+#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
+
+#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
+
+#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+
+/**
+ * Op mapping functions, which skip unsupported ops.
+ *
+ * Note: Do not use for LUTS, since these do not preserve ID order.
+ */
#define NULL_OP_FN(Type)
-#define MAP_MERGED_OPS(OP_FN) \
- MAP_OPS_BASED_ON_MERGEABILITY(NULL_OP_FN, OP_FN)
+#define MAP_MERGEABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
+
+#define MAP_RENDERABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
+
+#define MAP_DEFERRABLE_OPS(OP_FN) \
+ MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
namespace RecordedOpId {
enum {
- MAP_OPS(IDENTITY_FN)
+ MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
Count,
};
}
-static_assert(RecordedOpId::ArcOp == 0,
+static_assert(RecordedOpId::RenderNodeOp == 0,
"First index must be zero for LUTs to work");
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
-#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
+#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
+#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
+#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
struct RecordedOp {
/* ID from RecordedOpId - generally used for jumping into function tables */
@@ -103,8 +134,8 @@
/* transform in recording space (vs DisplayList origin) */
const Matrix4 localMatrix;
- /* clip in recording space */
- const Rect localClipRect;
+ /* clip in recording space - nullptr if not clipped */
+ const ClipBase* localClip;
/* optional paint, stored in base object to simplify merging logic */
const SkPaint* paint;
@@ -113,7 +144,7 @@
: opId(opId)
, unmappedBounds(unmappedBounds)
, localMatrix(localMatrix)
- , localClipRect(localClipRect)
+ , localClip(localClip)
, paint(paint) {}
};
@@ -184,9 +215,9 @@
};
struct CirclePropsOp : RecordedOp {
- CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+ CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* x, float* y, float* radius)
- : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint)
+ : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
, x(x)
, y(y)
, radius(radius) {}
@@ -195,6 +226,13 @@
const float* radius;
};
+struct FunctorOp : RecordedOp {
+ FunctorOp(BASE_PARAMS_PAINTLESS, Functor* functor)
+ : SUPER_PAINTLESS(FunctorOp)
+ , functor(functor) {}
+ Functor* functor;
+};
+
struct LinesOp : RecordedOp {
LinesOp(BASE_PARAMS, const float* points, const int floatCount)
: SUPER(LinesOp)
@@ -249,9 +287,9 @@
};
struct RoundRectPropsOp : RecordedOp {
- RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+ RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
float* left, float* top, float* right, float* bottom, float *rx, float *ry)
- : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint)
+ : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
, left(left)
, top(top)
, right(right)
@@ -276,12 +314,13 @@
*/
struct ShadowOp : RecordedOp {
ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
- const Rect& clipRect, const Vector3& lightCenter)
- : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
+ const Rect& localClipRect, const Vector3& lightCenter)
+ : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowMatrixXY(casterOp.localMatrix)
, shadowMatrixZ(casterOp.localMatrix)
, casterAlpha(casterAlpha)
, casterPath(casterPath)
+ , localClipRect(localClipRect)
, lightCenter(lightCenter) {
const RenderNode& node = *casterOp.renderNode;
node.applyViewPropertyTransforms(shadowMatrixXY, false);
@@ -291,6 +330,7 @@
Matrix4 shadowMatrixZ;
const float casterAlpha;
const SkPath* casterPath;
+ const Rect localClipRect;
const Vector3 lightCenter;
};
@@ -319,11 +359,34 @@
const float y;
};
+struct TextOnPathOp : RecordedOp {
+ TextOnPathOp(BASE_PARAMS, const glyph_t* glyphs, int glyphCount,
+ const SkPath* path, float hOffset, float vOffset)
+ : SUPER(TextOnPathOp)
+ , glyphs(glyphs)
+ , glyphCount(glyphCount)
+ , path(path)
+ , hOffset(hOffset)
+ , vOffset(vOffset) {}
+ const glyph_t* glyphs;
+ const int glyphCount;
+
+ const SkPath* path;
+ const float hOffset;
+ const float vOffset;
+};
+
+struct TextureLayerOp : RecordedOp {
+ TextureLayerOp(BASE_PARAMS_PAINTLESS, Layer* layer)
+ : SUPER_PAINTLESS(TextureLayerOp)
+ , layer(layer) {}
+ Layer* layer;
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Layers
////////////////////////////////////////////////////////////////////////////////////////////////////
-
/**
* Stateful operation! denotes the creation of an off-screen layer,
* and that commands following will render into it.
@@ -341,7 +404,7 @@
*/
struct EndLayerOp : RecordedOp {
EndLayerOp()
- : RecordedOp(RecordedOpId::EndLayerOp, Rect(0, 0), Matrix4::identity(), Rect(0, 0), nullptr) {}
+ : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
};
/**
@@ -355,13 +418,13 @@
LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
: SUPER_PAINTLESS(LayerOp)
, layerHandle(layerHandle)
- , alpha(paint->getAlpha() / 255.0f)
+ , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
, mode(PaintUtils::getXfermodeDirect(paint))
- , colorFilter(paint->getColorFilter())
+ , colorFilter(paint ? paint->getColorFilter() : nullptr)
, destroy(true) {}
LayerOp(RenderNode& node)
- : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), Rect(node.getWidth(), node.getHeight()), nullptr)
+ : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 1bf92be..f7f6caf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -16,6 +16,7 @@
#include "RecordingCanvas.h"
+#include "DeferredLayerUpdater.h"
#include "RecordedOp.h"
#include "RenderNode.h"
@@ -38,7 +39,7 @@
"prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
- mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());
+ mState.initializeRecordingSaveStack(width, height);
mDeferredBarrierType = DeferredBarrierType::InOrder;
mState.setDirtyClip(false);
@@ -154,6 +155,8 @@
return saveValue;
}
+ auto previousClip = getRecordedClip(); // note: done while snapshot == previous
+
snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight());
snapshot.transform->loadTranslate(-untransformedBounds.left, -untransformedBounds.top, 0.0f);
@@ -166,7 +169,7 @@
addOp(new (alloc()) BeginLayerOp(
Rect(left, top, right, bottom),
*previous.transform, // transform to *draw* with
- previous.getRenderTargetClip(), // clip to *draw* with
+ previousClip, // clip to *draw* with
refPaint(paint)));
return saveValue;
@@ -197,8 +200,7 @@
// Clip
bool RecordingCanvas::getClipBounds(SkRect* outRect) const {
- Rect bounds = mState.getLocalClipBounds();
- *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ *outRect = mState.getLocalClipBounds().toSkRect();
return !(outRect->isEmpty());
}
bool RecordingCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
@@ -229,11 +231,10 @@
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
- // TODO: more efficient recording?
addOp(new (alloc()) RectOp(
- mState.getRenderTargetClipBounds(),
+ mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
Matrix4::identity(),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -253,7 +254,7 @@
addOp(new (alloc()) PointsOp(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
@@ -264,7 +265,7 @@
addOp(new (alloc()) LinesOp(
calcBoundsOfPoints(points, floatCount),
*mState.currentSnapshot()->transform,
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
@@ -272,7 +273,7 @@
addOp(new (alloc()) RectOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -305,7 +306,7 @@
addOp(new (alloc()) SimpleRectsOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), rectData, vertexCount));
}
@@ -339,7 +340,7 @@
addOp(new (alloc()) RoundRectOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), rx, ry));
}
@@ -358,7 +359,7 @@
refBitmapsInShader(paint->value.getShader());
addOp(new (alloc()) RoundRectPropsOp(
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
&paint->value,
&left->value, &top->value, &right->value, &bottom->value,
&rx->value, &ry->value));
@@ -380,7 +381,7 @@
refBitmapsInShader(paint->value.getShader());
addOp(new (alloc()) CirclePropsOp(
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
&paint->value,
&x->value, &y->value, &radius->value));
}
@@ -390,7 +391,7 @@
addOp(new (alloc()) OvalOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint)));
}
@@ -399,7 +400,7 @@
addOp(new (alloc()) ArcOp(
Rect(left, top, right, bottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint),
startAngle, sweepAngle, useCenter));
}
@@ -408,7 +409,7 @@
addOp(new (alloc()) PathOp(
Rect(path.getBounds()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), refPath(&path)));
}
@@ -459,7 +460,7 @@
addOp(new (alloc()) BitmapRectOp(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap),
Rect(srcLeft, srcTop, srcRight, srcBottom)));
}
@@ -471,7 +472,7 @@
addOp(new (alloc()) BitmapMeshOp(
calcBoundsOfPoints(vertices, vertexCount * 2),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
refBuffer<int>(colors, vertexCount))); // 1 color per vertex
@@ -483,7 +484,7 @@
addOp(new (alloc()) PatchOp(
Rect(dstLeft, dstTop, dstRight, dstBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
@@ -499,29 +500,36 @@
addOp(new (alloc()) TextOp(
Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(&paint), glyphs, positions, glyphCount, x, y));
drawTextDecorations(x, y, totalAdvance, paint);
}
-void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
float hOffset, float vOffset, const SkPaint& paint) {
- LOG_ALWAYS_FATAL("TODO!");
+ if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
+ glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
+ addOp(new (alloc()) TextOnPathOp(
+ mState.getLocalClipBounds(), // TODO: explicitly define bounds
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(),
+ refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
}
void RecordingCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
addOp(new (alloc()) BitmapOp(
- Rect(0, 0, bitmap->width(), bitmap->height()),
+ Rect(bitmap->width(), bitmap->height()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
refPaint(paint), refBitmap(*bitmap)));
}
+
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
RenderNodeOp* op = new (alloc()) RenderNodeOp(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
*(mState.currentSnapshot()->transform),
- mState.getRenderTargetClipBounds(),
+ getRecordedClip(),
renderNode);
int opIndex = addOp(op);
int childIndex = mDisplayList->addChild(op);
@@ -536,6 +544,30 @@
}
}
+void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
+ // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
+ mDisplayList->ref(layerHandle);
+
+ Layer* layer = layerHandle->backingLayer();
+ Matrix4 totalTransform(*(mState.currentSnapshot()->transform));
+ totalTransform.multiply(layer->getTransform());
+
+ addOp(new (alloc()) TextureLayerOp(
+ Rect(layer->getWidth(), layer->getHeight()),
+ totalTransform,
+ getRecordedClip(),
+ layer));
+}
+
+void RecordingCanvas::callDrawGLFunction(Functor* functor) {
+ mDisplayList->functors.push_back(functor);
+ addOp(new (alloc()) FunctorOp(
+ mState.getLocalClipBounds(), // TODO: explicitly define bounds
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(),
+ functor));
+}
+
size_t RecordingCanvas::addOp(RecordedOp* op) {
// TODO: validate if "addDrawOp" quickrejection logic is useful before adding
int insertIndex = mDisplayList->ops.size();
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 6fbaa8a..1a2ac97f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -36,10 +36,11 @@
namespace android {
namespace uirenderer {
-class OpReceiver;
+struct ClipBase;
+class DeferredLayerUpdater;
struct RecordedOp;
-class RecordingCanvas: public Canvas, public CanvasStateClient {
+class ANDROID_API RecordingCanvas: public Canvas, public CanvasStateClient {
enum class DeferredBarrierType {
None,
InOrder,
@@ -59,8 +60,13 @@
mDeferredBarrierType = enableReorder
? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
}
+
+ void drawLayer(DeferredLayerUpdater* layerHandle);
void drawRenderNode(RenderNode* renderNode);
+ // TODO: rename for consistency
+ void callDrawGLFunction(Functor* functor);
+
// ----------------------------------------------------------------------------
// CanvasStateClient interface
// ----------------------------------------------------------------------------
@@ -186,14 +192,17 @@
const SkPaint* paint) override;
// Text
- virtual void drawText(const uint16_t* glyphs, const float* positions, int count,
+ virtual void drawText(const uint16_t* glyphs, const float* positions, int glyphCount,
const SkPaint& paint, float x, float y, float boundsLeft, float boundsTop,
float boundsRight, float boundsBottom, float totalAdvance) override;
- virtual void drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
+ virtual void drawTextOnPath(const uint16_t* glyphs, int glyphCount, const SkPath& path,
float hOffset, float vOffset, const SkPaint& paint) override;
virtual bool drawTextAbsolutePos() const override { return false; }
private:
+ const ClipBase* getRecordedClip() {
+ return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
+ }
void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index 2d5f70f..130cc80 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -138,15 +138,6 @@
SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
}
-void SkiaCanvasProxy::onDrawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint) {
- // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
- mCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
- mCanvas->setMatrix(SkMatrix::I());
- mCanvas->drawBitmap(bitmap, left, top, paint);
- mCanvas->restore();
-}
-
void SkiaCanvasProxy::onDrawVertices(VertexMode mode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*, const uint16_t indices[],
int indexCount, const SkPaint& paint) {
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 2fe4327..0089fb5 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -66,8 +66,6 @@
const SkPaint* paint, SrcRectConstraint) override;
virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
const SkRect& dst, const SkPaint*) override;
- virtual void onDrawSprite(const SkBitmap&, int left, int top,
- const SkPaint*) override;
virtual void onDrawVertices(VertexMode, int vertexCount, const SkPoint vertices[],
const SkPoint texs[], const SkColor colors[], SkXfermode*,
const uint16_t indices[], int indexCount,
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 2f535bb..c6d8977 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -88,9 +88,9 @@
mClipArea->clipRegion(region, op);
}
-void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+void Snapshot::clip(const Rect& localClip, SkRegion::Op op) {
flags |= Snapshot::kFlagClipSet;
- mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
+ mClipArea->clipRectWithTransform(localClip, transform, op);
}
void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 4789b33..5fac3a1 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -124,7 +124,7 @@
* the specified operation. The specified rectangle is transformed
* by this snapshot's trasnformation.
*/
- void clip(float left, float top, float right, float bottom, SkRegion::Op op);
+ void clip(const Rect& localClip, SkRegion::Op op);
/**
* Modifies the current clip with the new clip rectangle and
@@ -167,6 +167,7 @@
const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
bool clipIsSimple() const { return mClipArea->isSimple(); }
const ClipArea& getClipArea() const { return *mClipArea; }
+ ClipArea& mutateClipArea() { return *mClipArea; }
/**
* Resets the clip to the specified rect.
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
new file mode 100644
index 0000000..56cb104
--- /dev/null
+++ b/libs/hwui/VectorDrawable.cpp
@@ -0,0 +1,492 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "VectorDrawable.h"
+
+#include "PathParser.h"
+#include "SkImageInfo.h"
+#include <utils/Log.h>
+#include "utils/Macros.h"
+#include "utils/VectorDrawableUtils.h"
+
+#include <math.h>
+#include <string.h>
+
+namespace android {
+namespace uirenderer {
+namespace VectorDrawable {
+
+const int Tree::MAX_CACHED_BITMAP_SIZE = 2048;
+
+void Path::draw(Canvas* outCanvas, const SkMatrix& groupStackedMatrix, float scaleX, float scaleY) {
+ float matrixScale = getMatrixScale(groupStackedMatrix);
+ if (matrixScale == 0) {
+ // When either x or y is scaled to 0, we don't need to draw anything.
+ return;
+ }
+
+ const SkPath updatedPath = getUpdatedPath();
+ SkMatrix pathMatrix(groupStackedMatrix);
+ pathMatrix.postScale(scaleX, scaleY);
+
+ //TODO: try apply the path matrix to the canvas instead of creating a new path.
+ SkPath renderPath;
+ renderPath.reset();
+ renderPath.addPath(updatedPath, pathMatrix);
+
+ float minScale = fmin(scaleX, scaleY);
+ float strokeScale = minScale * matrixScale;
+ drawPath(outCanvas, renderPath, strokeScale);
+}
+
+void Path::setPathData(const Data& data) {
+ if (mData == data) {
+ return;
+ }
+ // Updates the path data. Note that we don't generate a new Skia path right away
+ // because there are cases where the animation is changing the path data, but the view
+ // that hosts the VD has gone off screen, in which case we won't even draw. So we
+ // postpone the Skia path generation to the draw time.
+ mData = data;
+ mSkPathDirty = true;
+}
+
+void Path::dump() {
+ ALOGD("Path: %s has %zu points", mName.c_str(), mData.points.size());
+}
+
+float Path::getMatrixScale(const SkMatrix& groupStackedMatrix) {
+ // Given unit vectors A = (0, 1) and B = (1, 0).
+ // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+ // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+ // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+ // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+ //
+ // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+ // scale on x and y axis, and take the minimal of these two.
+ // For skew case, an unit square will mapped to a parallelogram. And this function will
+ // return the minimal height of the 2 bases.
+ SkVector skVectors[2];
+ skVectors[0].set(0, 1);
+ skVectors[1].set(1, 0);
+ groupStackedMatrix.mapVectors(skVectors, 2);
+ float scaleX = hypotf(skVectors[0].fX, skVectors[0].fY);
+ float scaleY = hypotf(skVectors[1].fX, skVectors[1].fY);
+ float crossProduct = skVectors[0].cross(skVectors[1]);
+ float maxScale = fmax(scaleX, scaleY);
+
+ float matrixScale = 0;
+ if (maxScale > 0) {
+ matrixScale = fabs(crossProduct) / maxScale;
+ }
+ return matrixScale;
+}
+Path::Path(const char* pathStr, size_t strLength) {
+ PathParser::ParseResult result;
+ PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+ if (!result.failureOccurred) {
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ }
+}
+
+Path::Path(const Data& data) {
+ mData = data;
+ // Now we need to construct a path
+ VectorDrawableUtils::verbsToPath(&mSkPath, data);
+}
+
+Path::Path(const Path& path) : Node(path) {
+ mData = path.mData;
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+}
+
+bool Path::canMorph(const Data& morphTo) {
+ return VectorDrawableUtils::canMorph(mData, morphTo);
+}
+
+bool Path::canMorph(const Path& path) {
+ return canMorph(path.mData);
+}
+
+const SkPath& Path::getUpdatedPath() {
+ if (mSkPathDirty) {
+ mSkPath.reset();
+ VectorDrawableUtils::verbsToPath(&mSkPath, mData);
+ mSkPathDirty = false;
+ }
+ return mSkPath;
+}
+
+void Path::setPath(const char* pathStr, size_t strLength) {
+ PathParser::ParseResult result;
+ mSkPathDirty = true;
+ PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
+}
+
+FullPath::FullPath(const FullPath& path) : Path(path) {
+ mStrokeWidth = path.mStrokeWidth;
+ mStrokeColor = path.mStrokeColor;
+ mStrokeAlpha = path.mStrokeAlpha;
+ mFillColor = path.mFillColor;
+ mFillAlpha = path.mFillAlpha;
+ mTrimPathStart = path.mTrimPathStart;
+ mTrimPathEnd = path.mTrimPathEnd;
+ mTrimPathOffset = path.mTrimPathOffset;
+ mStrokeMiterLimit = path.mStrokeMiterLimit;
+ mStrokeLineCap = path.mStrokeLineCap;
+ mStrokeLineJoin = path.mStrokeLineJoin;
+}
+
+const SkPath& FullPath::getUpdatedPath() {
+ if (!mSkPathDirty && !mTrimDirty) {
+ return mTrimmedSkPath;
+ }
+ Path::getUpdatedPath();
+ if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+ applyTrim();
+ return mTrimmedSkPath;
+ } else {
+ return mSkPath;
+ }
+}
+
+void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
+ SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
+ float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) {
+ mStrokeWidth = strokeWidth;
+ mStrokeColor = strokeColor;
+ mStrokeAlpha = strokeAlpha;
+ mFillColor = fillColor;
+ mFillAlpha = fillAlpha;
+ mStrokeMiterLimit = strokeMiterLimit;
+ mStrokeLineCap = SkPaint::Cap(strokeLineCap);
+ mStrokeLineJoin = SkPaint::Join(strokeLineJoin);
+
+ // If any trim property changes, mark trim dirty and update the trim path
+ setTrimPathStart(trimPathStart);
+ setTrimPathEnd(trimPathEnd);
+ setTrimPathOffset(trimPathOffset);
+}
+
+inline SkColor applyAlpha(SkColor color, float alpha) {
+ int alphaBytes = SkColorGetA(color);
+ return SkColorSetA(color, alphaBytes * alpha);
+}
+
+void FullPath::drawPath(Canvas* outCanvas, const SkPath& renderPath, float strokeScale){
+ // Draw path's fill, if fill color isn't transparent.
+ if (mFillColor != SK_ColorTRANSPARENT) {
+ mPaint.setStyle(SkPaint::Style::kFill_Style);
+ mPaint.setAntiAlias(true);
+ mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+ outCanvas->drawPath(renderPath, mPaint);
+ }
+ // Draw path's stroke, if stroke color isn't transparent
+ if (mStrokeColor != SK_ColorTRANSPARENT) {
+ mPaint.setStyle(SkPaint::Style::kStroke_Style);
+ mPaint.setAntiAlias(true);
+ mPaint.setStrokeJoin(mStrokeLineJoin);
+ mPaint.setStrokeCap(mStrokeLineCap);
+ mPaint.setStrokeMiter(mStrokeMiterLimit);
+ mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+ mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
+ outCanvas->drawPath(renderPath, mPaint);
+ }
+}
+
+/**
+ * Applies trimming to the specified path.
+ */
+void FullPath::applyTrim() {
+ if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+ // No trimming necessary.
+ return;
+ }
+ SkPathMeasure measure(mSkPath, false);
+ float len = SkScalarToFloat(measure.getLength());
+ float start = len * fmod((mTrimPathStart + mTrimPathOffset), 1.0f);
+ float end = len * fmod((mTrimPathEnd + mTrimPathOffset), 1.0f);
+
+ mTrimmedSkPath.reset();
+ if (start > end) {
+ measure.getSegment(start, len, &mTrimmedSkPath, true);
+ measure.getSegment(0, end, &mTrimmedSkPath, true);
+ } else {
+ measure.getSegment(start, end, &mTrimmedSkPath, true);
+ }
+ mTrimDirty = false;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, float value) {
+ int size = sizeof(float);
+ memcpy(&outBytes[startIndex], &value, size);
+ return size;
+}
+
+inline int putData(int8_t* outBytes, int startIndex, int value) {
+ int size = sizeof(int);
+ memcpy(&outBytes[startIndex], &value, size);
+ return size;
+}
+
+struct FullPathProperties {
+ // TODO: Consider storing full path properties in this struct instead of the fields.
+ float strokeWidth;
+ SkColor strokeColor;
+ float strokeAlpha;
+ SkColor fillColor;
+ float fillAlpha;
+ float trimPathStart;
+ float trimPathEnd;
+ float trimPathOffset;
+ int32_t strokeLineCap;
+ int32_t strokeLineJoin;
+ float strokeMiterLimit;
+};
+
+REQUIRE_COMPATIBLE_LAYOUT(FullPathProperties);
+
+static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
+static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
+
+bool FullPath::getProperties(int8_t* outProperties, int length) {
+ int propertyDataSize = sizeof(FullPathProperties);
+ if (length != propertyDataSize) {
+ LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
+ propertyDataSize, length);
+ return false;
+ }
+ // TODO: consider replacing the property fields with a FullPathProperties struct.
+ FullPathProperties properties;
+ properties.strokeWidth = mStrokeWidth;
+ properties.strokeColor = mStrokeColor;
+ properties.strokeAlpha = mStrokeAlpha;
+ properties.fillColor = mFillColor;
+ properties.fillAlpha = mFillAlpha;
+ properties.trimPathStart = mTrimPathStart;
+ properties.trimPathEnd = mTrimPathEnd;
+ properties.trimPathOffset = mTrimPathOffset;
+ properties.strokeLineCap = mStrokeLineCap;
+ properties.strokeLineJoin = mStrokeLineJoin;
+ properties.strokeMiterLimit = mStrokeMiterLimit;
+
+ memcpy(outProperties, &properties, length);
+ return true;
+}
+
+void ClipPath::drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale){
+ outCanvas->clipPath(&renderPath, SkRegion::kIntersect_Op);
+}
+
+Group::Group(const Group& group) : Node(group) {
+ mRotate = group.mRotate;
+ mPivotX = group.mPivotX;
+ mPivotY = group.mPivotY;
+ mScaleX = group.mScaleX;
+ mScaleY = group.mScaleY;
+ mTranslateX = group.mTranslateX;
+ mTranslateY = group.mTranslateY;
+}
+
+void Group::draw(Canvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
+ float scaleY) {
+ // TODO: Try apply the matrix to the canvas instead of passing it down the tree
+
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ SkMatrix stackedMatrix;
+ getLocalMatrix(&stackedMatrix);
+ stackedMatrix.postConcat(currentMatrix);
+
+ // Save the current clip information, which is local to this group.
+ outCanvas->save(SkCanvas::kMatrixClip_SaveFlag);
+ // Draw the group tree in the same order as the XML file.
+ for (Node* child : mChildren) {
+ child->draw(outCanvas, stackedMatrix, scaleX, scaleY);
+ }
+ // Restore the previous clip information.
+ outCanvas->restore();
+}
+
+void Group::dump() {
+ ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
+ for (size_t i = 0; i < mChildren.size(); i++) {
+ mChildren[i]->dump();
+ }
+}
+
+void Group::updateLocalMatrix(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY) {
+ setRotation(rotate);
+ setPivotX(pivotX);
+ setPivotY(pivotY);
+ setScaleX(scaleX);
+ setScaleY(scaleY);
+ setTranslateX(translateX);
+ setTranslateY(translateY);
+}
+
+void Group::getLocalMatrix(SkMatrix* outMatrix) {
+ outMatrix->reset();
+ // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
+ // translating to pivot for rotating and scaling, then translating back.
+ outMatrix->postTranslate(-mPivotX, -mPivotY);
+ outMatrix->postScale(mScaleX, mScaleY);
+ outMatrix->postRotate(mRotate, 0, 0);
+ outMatrix->postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+}
+
+void Group::addChild(Node* child) {
+ mChildren.push_back(child);
+}
+
+bool Group::getProperties(float* outProperties, int length) {
+ int propertyCount = static_cast<int>(Property::Count);
+ if (length != propertyCount) {
+ LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
+ propertyCount, length);
+ return false;
+ }
+ for (int i = 0; i < propertyCount; i++) {
+ Property currentProperty = static_cast<Property>(i);
+ switch (currentProperty) {
+ case Property::Rotate_Property:
+ outProperties[i] = mRotate;
+ break;
+ case Property::PivotX_Property:
+ outProperties[i] = mPivotX;
+ break;
+ case Property::PivotY_Property:
+ outProperties[i] = mPivotY;
+ break;
+ case Property::ScaleX_Property:
+ outProperties[i] = mScaleX;
+ break;
+ case Property::ScaleY_Property:
+ outProperties[i] = mScaleY;
+ break;
+ case Property::TranslateX_Property:
+ outProperties[i] = mTranslateX;
+ break;
+ case Property::TranslateY_Property:
+ outProperties[i] = mTranslateY;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid input index: %d", i);
+ return false;
+ }
+ }
+ return true;
+}
+
+void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+ const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
+ // The imageView can scale the canvas in different ways, in order to
+ // avoid blurry scaling, we have to draw into a bitmap with exact pixel
+ // size first. This bitmap size is determined by the bounds and the
+ // canvas scale.
+ outCanvas->getMatrix(&mCanvasMatrix);
+ mBounds = bounds;
+ float canvasScaleX = 1.0f;
+ float canvasScaleY = 1.0f;
+ if (mCanvasMatrix.getSkewX() == 0 && mCanvasMatrix.getSkewY() == 0) {
+ // Only use the scale value when there's no skew or rotation in the canvas matrix.
+ canvasScaleX = mCanvasMatrix.getScaleX();
+ canvasScaleY = mCanvasMatrix.getScaleY();
+ }
+ int scaledWidth = (int) (mBounds.width() * canvasScaleX);
+ int scaledHeight = (int) (mBounds.height() * canvasScaleY);
+ scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
+ scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
+
+ if (scaledWidth <= 0 || scaledHeight <= 0) {
+ return;
+ }
+
+ int saveCount = outCanvas->save(SkCanvas::SaveFlags::kMatrixClip_SaveFlag);
+ outCanvas->translate(mBounds.fLeft, mBounds.fTop);
+
+ // Handle RTL mirroring.
+ if (needsMirroring) {
+ outCanvas->translate(mBounds.width(), 0);
+ outCanvas->scale(-1.0f, 1.0f);
+ }
+
+ // At this point, canvas has been translated to the right position.
+ // And we use this bound for the destination rect for the drawBitmap, so
+ // we offset to (0, 0);
+ mBounds.offsetTo(0, 0);
+
+ createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
+ if (!mAllowCaching) {
+ updateCachedBitmap(scaledWidth, scaledHeight);
+ } else {
+ if (!canReuseCache || mCacheDirty) {
+ updateCachedBitmap(scaledWidth, scaledHeight);
+ }
+ }
+ drawCachedBitmapWithRootAlpha(outCanvas, colorFilter, mBounds);
+
+ outCanvas->restoreToCount(saveCount);
+}
+
+void Tree::drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+ const SkRect& originalBounds) {
+ SkPaint* paint;
+ if (mRootAlpha == 1.0f && filter == NULL) {
+ paint = NULL;
+ } else {
+ mPaint.setFilterQuality(kLow_SkFilterQuality);
+ mPaint.setAlpha(mRootAlpha * 255);
+ mPaint.setColorFilter(filter);
+ paint = &mPaint;
+ }
+ outCanvas->drawBitmap(mCachedBitmap, 0, 0, mCachedBitmap.width(), mCachedBitmap.height(),
+ originalBounds.fLeft, originalBounds.fTop, originalBounds.fRight,
+ originalBounds.fBottom, paint);
+}
+
+void Tree::updateCachedBitmap(int width, int height) {
+ mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
+ Canvas* outCanvas = Canvas::create_canvas(mCachedBitmap);
+ float scaleX = width / mViewportWidth;
+ float scaleY = height / mViewportHeight;
+ mRootNode->draw(outCanvas, SkMatrix::I(), scaleX, scaleY);
+ mCacheDirty = false;
+}
+
+void Tree::createCachedBitmapIfNeeded(int width, int height) {
+ if (!canReuseBitmap(width, height)) {
+ SkImageInfo info = SkImageInfo::Make(width, height,
+ kN32_SkColorType, kPremul_SkAlphaType);
+ mCachedBitmap.setInfo(info);
+ // TODO: Count the bitmap cache against app's java heap
+ mCachedBitmap.allocPixels(info);
+ mCacheDirty = true;
+ }
+}
+
+bool Tree::canReuseBitmap(int width, int height) {
+ return width == mCachedBitmap.width() && height == mCachedBitmap.height();
+}
+
+}; // namespace VectorDrawable
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
new file mode 100644
index 0000000..6c84b05
--- /dev/null
+++ b/libs/hwui/VectorDrawable.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWUI_VPATH_H
+#define ANDROID_HWUI_VPATH_H
+
+#include "Canvas.h"
+#include <SkBitmap.h>
+#include <SkColor.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkPath.h>
+#include <SkPathMeasure.h>
+#include <SkRect.h>
+
+#include <cutils/compiler.h>
+#include <stddef.h>
+#include <vector>
+#include <string>
+
+namespace android {
+namespace uirenderer {
+
+namespace VectorDrawable {
+#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP(field, value) ? (flag = true, true): false);
+#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
+
+/* A VectorDrawable is composed of a tree of nodes.
+ * Each node can be a group node, or a path.
+ * A group node can have groups or paths as children, but a path node has
+ * no children.
+ * One example can be:
+ * Root Group
+ * / | \
+ * Group Path Group
+ * / \ |
+ * Path Path Path
+ *
+ */
+class ANDROID_API Node {
+public:
+ Node(const Node& node) {
+ mName = node.mName;
+ }
+ Node() {}
+ virtual void draw(Canvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY) = 0;
+ virtual void dump() = 0;
+ void setName(const char* name) {
+ mName = name;
+ }
+ virtual ~Node(){}
+protected:
+ std::string mName;
+};
+
+class ANDROID_API Path : public Node {
+public:
+ struct ANDROID_API Data {
+ std::vector<char> verbs;
+ std::vector<size_t> verbSizes;
+ std::vector<float> points;
+ bool operator==(const Data& data) const {
+ return verbs == data.verbs && verbSizes == data.verbSizes
+ && points == data.points;
+ }
+ };
+ Path(const Data& nodes);
+ Path(const Path& path);
+ Path(const char* path, size_t strLength);
+ Path() {}
+ void dump() override;
+ bool canMorph(const Data& path);
+ bool canMorph(const Path& path);
+ void draw(Canvas* outCanvas, const SkMatrix& groupStackedMatrix,
+ float scaleX, float scaleY) override;
+ void setPath(const char* path, size_t strLength);
+ void setPathData(const Data& data);
+ static float getMatrixScale(const SkMatrix& groupStackedMatrix);
+
+protected:
+ virtual const SkPath& getUpdatedPath();
+ virtual void drawPath(Canvas *outCanvas, const SkPath& renderPath,
+ float strokeScale) = 0;
+ Data mData;
+ SkPath mSkPath;
+ bool mSkPathDirty = true;
+};
+
+class ANDROID_API FullPath: public Path {
+public:
+ FullPath(const FullPath& path); // for cloning
+ FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
+ FullPath() : Path() {}
+ FullPath(const Data& nodes) : Path(nodes) {}
+
+ void updateProperties(float strokeWidth, SkColor strokeColor,
+ float strokeAlpha, SkColor fillColor, float fillAlpha,
+ float trimPathStart, float trimPathEnd, float trimPathOffset,
+ float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+ SkColor getStrokeColor() {
+ return mStrokeColor;
+ }
+ void setStrokeColor(SkColor strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+ float getStrokeAlpha() {
+ return mStrokeAlpha;
+ }
+ void setStrokeAlpha(float strokeAlpha) {
+ mStrokeAlpha = strokeAlpha;
+ }
+ SkColor getFillColor() {
+ return mFillColor;
+ }
+ void setFillColor(SkColor fillColor) {
+ mFillColor = fillColor;
+ }
+ float getFillAlpha() {
+ return mFillAlpha;
+ }
+ void setFillAlpha(float fillAlpha) {
+ mFillAlpha = fillAlpha;
+ }
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+ void setTrimPathStart(float trimPathStart) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathStart, trimPathStart, mTrimDirty);
+ }
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+ void setTrimPathEnd(float trimPathEnd) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathEnd, trimPathEnd, mTrimDirty);
+ }
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+ void setTrimPathOffset(float trimPathOffset) {
+ VD_SET_PROP_WITH_FLAG(mTrimPathOffset, trimPathOffset, mTrimDirty);
+ }
+ bool getProperties(int8_t* outProperties, int length);
+
+protected:
+ const SkPath& getUpdatedPath() override;
+ void drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale) override;
+
+private:
+ // Applies trimming to the specified path.
+ void applyTrim();
+ float mStrokeWidth = 0;
+ SkColor mStrokeColor = SK_ColorTRANSPARENT;
+ float mStrokeAlpha = 1;
+ SkColor mFillColor = SK_ColorTRANSPARENT;
+ float mFillAlpha = 1;
+ float mTrimPathStart = 0;
+ float mTrimPathEnd = 1;
+ float mTrimPathOffset = 0;
+ bool mTrimDirty = true;
+ SkPaint::Cap mStrokeLineCap = SkPaint::Cap::kButt_Cap;
+ SkPaint::Join mStrokeLineJoin = SkPaint::Join::kMiter_Join;
+ float mStrokeMiterLimit = 4;
+ SkPath mTrimmedSkPath;
+ SkPaint mPaint;
+};
+
+class ANDROID_API ClipPath: public Path {
+public:
+ ClipPath(const ClipPath& path) : Path(path) {}
+ ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
+ ClipPath() : Path() {}
+ ClipPath(const Data& nodes) : Path(nodes) {}
+
+protected:
+ void drawPath(Canvas* outCanvas, const SkPath& renderPath,
+ float strokeScale) override;
+};
+
+class ANDROID_API Group: public Node {
+public:
+ Group(const Group& group);
+ Group() {}
+ float getRotation() {
+ return mRotate;
+ }
+ void setRotation(float rotation) {
+ mRotate = rotation;
+ }
+ float getPivotX() {
+ return mPivotX;
+ }
+ void setPivotX(float pivotX) {
+ mPivotX = pivotX;
+ }
+ float getPivotY() {
+ return mPivotY;
+ }
+ void setPivotY(float pivotY) {
+ mPivotY = pivotY;
+ }
+ float getScaleX() {
+ return mScaleX;
+ }
+ void setScaleX(float scaleX) {
+ mScaleX = scaleX;
+ }
+ float getScaleY() {
+ return mScaleY;
+ }
+ void setScaleY(float scaleY) {
+ mScaleY = scaleY;
+ }
+ float getTranslateX() {
+ return mTranslateX;
+ }
+ void setTranslateX(float translateX) {
+ mTranslateX = translateX;
+ }
+ float getTranslateY() {
+ return mTranslateY;
+ }
+ void setTranslateY(float translateY) {
+ mTranslateY = translateY;
+ }
+ virtual void draw(Canvas* outCanvas, const SkMatrix& currentMatrix,
+ float scaleX, float scaleY) override;
+ void updateLocalMatrix(float rotate, float pivotX, float pivotY,
+ float scaleX, float scaleY, float translateX, float translateY);
+ void getLocalMatrix(SkMatrix* outMatrix);
+ void addChild(Node* child);
+ void dump() override;
+ bool getProperties(float* outProperties, int length);
+
+private:
+ enum class Property {
+ Rotate_Property = 0,
+ PivotX_Property,
+ PivotY_Property,
+ ScaleX_Property,
+ ScaleY_Property,
+ TranslateX_Property,
+ TranslateY_Property,
+ // Count of the properties, must be at the end.
+ Count,
+ };
+ float mRotate = 0;
+ float mPivotX = 0;
+ float mPivotY = 0;
+ float mScaleX = 1;
+ float mScaleY = 1;
+ float mTranslateX = 0;
+ float mTranslateY = 0;
+ std::vector<Node*> mChildren;
+};
+
+class ANDROID_API Tree {
+public:
+ Tree(Group* rootNode) : mRootNode(rootNode) {}
+ void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
+ const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ void drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
+ const SkRect& originalBounds);
+
+ void updateCachedBitmap(int width, int height);
+ void createCachedBitmapIfNeeded(int width, int height);
+ bool canReuseBitmap(int width, int height);
+ void setAllowCaching(bool allowCaching) {
+ mAllowCaching = allowCaching;
+ }
+ bool setRootAlpha(float rootAlpha) {
+ return VD_SET_PROP(mRootAlpha, rootAlpha);
+ }
+
+ float getRootAlpha() {
+ return mRootAlpha;
+ }
+ void setViewportSize(float viewportWidth, float viewportHeight) {
+ mViewportWidth = viewportWidth;
+ mViewportHeight = viewportHeight;
+ }
+
+private:
+ // Cap the bitmap size, such that it won't hurt the performance too much
+ // and it won't crash due to a very large scale.
+ // The drawable will look blurry above this size.
+ const static int MAX_CACHED_BITMAP_SIZE;
+
+ bool mCacheDirty = true;
+ bool mAllowCaching = true;
+ float mViewportWidth = 0;
+ float mViewportHeight = 0;
+ float mRootAlpha = 1.0f;
+
+ Group* mRootNode;
+ SkRect mBounds;
+ SkMatrix mCanvasMatrix;
+ SkPaint mPaint;
+ SkPathMeasure mPathMeasure;
+ SkBitmap mCachedBitmap;
+
+};
+
+} // namespace VectorDrawable
+
+typedef VectorDrawable::Path::Data PathData;
+} // namespace uirenderer
+} // namespace android
+
+#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/VectorDrawablePath.cpp b/libs/hwui/VectorDrawablePath.cpp
deleted file mode 100644
index c9a54ca..0000000
--- a/libs/hwui/VectorDrawablePath.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 "VectorDrawablePath.h"
-
-#include "PathParser.h"
-#include "utils/VectorDrawableUtils.h"
-
-#include <math.h>
-#include <utils/Log.h>
-
-namespace android {
-namespace uirenderer {
-
-
-VectorDrawablePath::VectorDrawablePath(const char* pathStr, size_t strLength) {
- PathParser::ParseResult result;
- PathParser::getPathDataFromString(&mData, &result, pathStr, strLength);
- if (!result.failureOccurred) {
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
- }
-}
-
-VectorDrawablePath::VectorDrawablePath(const PathData& data) {
- mData = data;
- // Now we need to construct a path
- VectorDrawableUtils::verbsToPath(&mSkPath, data);
-}
-
-VectorDrawablePath::VectorDrawablePath(const VectorDrawablePath& path) {
- mData = path.mData;
- VectorDrawableUtils::verbsToPath(&mSkPath, mData);
-}
-
-
-bool VectorDrawablePath::canMorph(const PathData& morphTo) {
- return VectorDrawableUtils::canMorph(mData, morphTo);
-}
-
-bool VectorDrawablePath::canMorph(const VectorDrawablePath& path) {
- return canMorph(path.mData);
-}
-
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/VectorDrawablePath.h b/libs/hwui/VectorDrawablePath.h
deleted file mode 100644
index 2e56349..0000000
--- a/libs/hwui/VectorDrawablePath.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_VPATH_H
-#define ANDROID_HWUI_VPATH_H
-
-#include <cutils/compiler.h>
-#include "SkPath.h"
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-struct ANDROID_API PathData {
- // TODO: Try using FatVector instead of std::vector and do a micro benchmark on the performance
- // difference.
- std::vector<char> verbs;
- std::vector<size_t> verbSizes;
- std::vector<float> points;
- bool operator== (const PathData& data) const {
- return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
- }
-
-};
-
-class VectorDrawablePath {
-public:
- VectorDrawablePath(const PathData& nodes);
- VectorDrawablePath(const VectorDrawablePath& path);
- VectorDrawablePath(const char* path, size_t strLength);
- bool canMorph(const PathData& path);
- bool canMorph(const VectorDrawablePath& path);
-
-private:
- PathData mData;
- SkPath mSkPath;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 95dcd18..61dd8c3 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -15,6 +15,8 @@
*/
#include "renderstate/Scissor.h"
+#include "Rect.h"
+
#include <utils/Log.h>
namespace android {
@@ -71,6 +73,26 @@
return false;
}
+void Scissor::set(int viewportHeight, const Rect& clip) {
+ // transform to Y-flipped GL space, and prevent negatives
+ GLint x = std::max(0, (int)clip.left);
+ GLint y = std::max(0, viewportHeight - (int)clip.bottom);
+ GLint width = std::max(0, ((int)clip.right) - x);
+ GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
+
+ if (x != mScissorX
+ || y != mScissorY
+ || width != mScissorWidth
+ || height != mScissorHeight) {
+ glScissor(x, y, width, height);
+
+ mScissorX = x;
+ mScissorY = y;
+ mScissorWidth = width;
+ mScissorHeight = height;
+ }
+}
+
void Scissor::reset() {
mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
}
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index b37ec58..f302244 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -22,11 +22,14 @@
namespace android {
namespace uirenderer {
+class Rect;
+
class Scissor {
friend class RenderState;
public:
bool setEnabled(bool enabled);
bool set(GLint x, GLint y, GLint width, GLint height);
+ void set(int viewportHeight, const Rect& clip);
void reset();
bool isEnabled() { return mEnabled; }
void dump();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ca85dfb..1af8f80 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -128,14 +128,13 @@
mSwapBehavior = swapBehavior;
}
-bool CanvasContext::initialize(ANativeWindow* window) {
+void CanvasContext::initialize(ANativeWindow* window) {
setSurface(window);
#if !HWUI_NEW_OPS
- if (mCanvas) return false;
+ if (mCanvas) return;
mCanvas = new OpenGLRenderer(mRenderThread.renderState());
mCanvas->initProperties();
#endif
- return true;
}
void CanvasContext::updateSurface(ANativeWindow* window) {
@@ -182,16 +181,6 @@
}
}
-void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
-#if !HWUI_NEW_OPS
- bool success = layerUpdater->apply();
- LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
- if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
- mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
- }
-#endif
-}
-
static bool wasSkipped(FrameInfo* info) {
return info && ((*info)[FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame);
}
@@ -513,9 +502,11 @@
// Called by choreographer to do an RT-driven animation
void CanvasContext::doFrame() {
- if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) {
- return;
- }
+#if HWUI_NEW_OPS
+ if (CC_UNLIKELY(mEglSurface == EGL_NO_SURFACE)) return;
+#else
+ if (CC_UNLIKELY(!mCanvas || mEglSurface == EGL_NO_SURFACE)) return;
+#endif
prepareAndDraw(nullptr);
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d36ce99..8e64cbb 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -73,7 +73,7 @@
// Won't take effect until next EGLSurface creation
void setSwapBehavior(SwapBehavior swapBehavior);
- bool initialize(ANativeWindow* window);
+ void initialize(ANativeWindow* window);
void updateSurface(ANativeWindow* window);
bool pauseSurface(ANativeWindow* window);
bool hasSurface() { return mNativeWindow.get(); }
@@ -83,7 +83,6 @@
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
void makeCurrent();
- void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index ab860c7..e8b9725 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -117,7 +117,7 @@
Caches::getInstance().textureCache.resetMarkInUse(mContext);
for (size_t i = 0; i < mLayers.size(); i++) {
- mContext->processLayerUpdate(mLayers[i].get());
+ mLayers[i]->apply();
}
mLayers.clear();
mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 78df297..466fef9d 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -29,8 +29,6 @@
#define GLES_VERSION 2
-#define WAIT_FOR_GPU_COMPLETION 0
-
// Android-specific addition that is used to show when frames began in systrace
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -179,7 +177,10 @@
}
void EglManager::createContext() {
- EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE };
+ EGLint attribs[] = {
+ EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
+ EGL_NONE
+ };
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
"Failed to create context, error = %s", egl_error_str());
@@ -318,12 +319,10 @@
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
-#if WAIT_FOR_GPU_COMPLETION
- {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
fence();
}
-#endif
EGLint rects[4];
frame.map(screenDirty, rects);
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 15ccd6a..43282c9 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -140,14 +140,15 @@
}
CREATE_BRIDGE2(initialize, CanvasContext* context, ANativeWindow* window) {
- return (void*) args->context->initialize(args->window);
+ args->context->initialize(args->window);
+ return nullptr;
}
-bool RenderProxy::initialize(const sp<ANativeWindow>& window) {
+void RenderProxy::initialize(const sp<ANativeWindow>& window) {
SETUP_TASK(initialize);
args->context = mContext;
args->window = window.get();
- return (bool) postAndWait(task);
+ post(task);
}
CREATE_BRIDGE2(updateSurface, CanvasContext* context, ANativeWindow* window) {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 338fab6..1d30eb8 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -66,7 +66,7 @@
ANDROID_API bool loadSystemProperties();
ANDROID_API void setName(const char* name);
- ANDROID_API bool initialize(const sp<ANativeWindow>& window);
+ ANDROID_API void initialize(const sp<ANativeWindow>& window);
ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
ANDROID_API void setup(int width, int height, float lightRadius,
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index df8d194..706f2ff 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -37,6 +37,7 @@
public:
struct Options {
int count = 0;
+ int reportFrametimeWeight = 0;
};
template <class T>
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 6cef852..624f3bd 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,6 +16,9 @@
#include "TestUtils.h"
+#include "DeferredLayerUpdater.h"
+#include "LayerRenderer.h"
+
namespace android {
namespace uirenderer {
@@ -36,16 +39,29 @@
| (int)((startB + (int)(fraction * (endB - startB))));
}
+sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
+ renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
+ std::function<void(Matrix4*)> transformSetupCallback) {
+ bool isOpaque = true;
+ bool forceFilter = true;
+ GLenum renderTarget = GL_TEXTURE_EXTERNAL_OES;
+
+ Layer* layer = LayerRenderer::createTextureLayer(renderThread.renderState());
+ LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, forceFilter,
+ renderTarget, Matrix4::identity().data);
+ transformSetupCallback(&(layer->getTransform()));
+
+ sp<DeferredLayerUpdater> layerUpdater = new DeferredLayerUpdater(layer);
+ return layerUpdater;
+}
+
void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
const SkPaint& paint, float x, float y) {
// drawing text requires GlyphID TextEncoding (which JNI layer would have done)
LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
"must use glyph encoding");
-
- SkMatrix identity;
- identity.setIdentity();
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &identity);
+ SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
float totalAdvance = 0;
std::vector<glyph_t> glyphs;
@@ -89,5 +105,21 @@
bounds.left, bounds.top, bounds.right, bounds.bottom, totalAdvance);
}
+void TestUtils::drawTextToCanvas(TestCanvas* canvas, const char* text,
+ const SkPaint& paint, const SkPath& path) {
+ // drawing text requires GlyphID TextEncoding (which JNI layer would have done)
+ LOG_ALWAYS_FATAL_IF(paint.getTextEncoding() != SkPaint::kGlyphID_TextEncoding,
+ "must use glyph encoding");
+ SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
+ SkAutoGlyphCacheNoGamma autoCache(paint, &surfaceProps, &SkMatrix::I());
+
+ std::vector<glyph_t> glyphs;
+ while (*text != '\0') {
+ SkUnichar unichar = SkUTF8_NextUnichar(&text);
+ glyphs.push_back(autoCache.getCache()->unicharToGlyph(unichar));
+ }
+ canvas->drawTextOnPath(glyphs.data(), glyphs.size(), path, 0, 0, paint);
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 0af9939..ac14fc8 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -98,7 +98,7 @@
static std::unique_ptr<Snapshot> makeSnapshot(const Matrix4& transform, const Rect& clip) {
std::unique_ptr<Snapshot> snapshot(new Snapshot());
- snapshot->clip(clip.left, clip.top, clip.right, clip.bottom, SkRegion::kReplace_Op);
+ snapshot->clip(clip, SkRegion::kReplace_Op); // store clip first, so it isn't transformed
*(snapshot->transform) = transform;
return snapshot;
}
@@ -113,6 +113,10 @@
return bitmap;
}
+ static sp<DeferredLayerUpdater> createTextureLayerUpdater(
+ renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
+ std::function<void(Matrix4*)> transformSetupCallback);
+
template<class CanvasType>
static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
std::function<void(CanvasType& canvas)> canvasCallback) {
@@ -191,6 +195,9 @@
static void drawTextToCanvas(TestCanvas* canvas, const char* text,
const SkPaint& paint, float x, float y);
+ static void drawTextToCanvas(TestCanvas* canvas, const char* text,
+ const SkPaint& paint, const SkPath& path);
+
private:
static void syncHierarchyPropertiesAndDisplayListImpl(RenderNode* node) {
node->syncProperties();
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
new file mode 100644
index 0000000..db6402c
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "TestSceneBase.h"
+
+class ClippingAnimation;
+
+static TestScene::Registrar _RectGrid(TestScene::Info{
+ "clip",
+ "Complex clip cases"
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<ClippingAnimation>
+});
+
+class ClippingAnimation : public TestScene {
+public:
+ sp<RenderNode> card;
+ void createContent(int width, int height, TestCanvas& canvas) override {
+ canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+ card = TestUtils::createNode(0, 0, 200, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ {
+ canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+ canvas.translate(100, 100);
+ canvas.rotate(45);
+ canvas.translate(-100, -100);
+ canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+ canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode);
+ }
+ canvas.restore();
+
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ {
+ SkPath clipCircle;
+ clipCircle.addCircle(100, 300, 100);
+ canvas.clipPath(&clipCircle, SkRegion::kIntersect_Op);
+ canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+ }
+ canvas.restore();
+
+ // put on a layer, to test stencil attachment
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ props.setAlpha(0.9f);
+ });
+ canvas.drawRenderNode(card.get());
+ }
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 150;
+ card->mutateStagingProperties().setTranslationX(curFrame);
+ card->mutateStagingProperties().setTranslationY(curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+};
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 082c628..e56f2f9 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -15,6 +15,7 @@
*/
#include "TestSceneBase.h"
+#include "utils/Color.h"
class OvalAnimation;
@@ -28,12 +29,12 @@
public:
sp<RenderNode> card;
void createContent(int width, int height, TestCanvas& canvas) override {
- canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+ canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
card = TestUtils::createNode(0, 0, 200, 200,
[](RenderProperties& props, TestCanvas& canvas) {
SkPaint paint;
paint.setAntiAlias(true);
- paint.setColor(0xFF000000);
+ paint.setColor(Color::Black);
canvas.drawOval(0, 0, 200, 200, paint);
});
canvas.drawRenderNode(card.get());
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index ac78124..935ddcf 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -22,6 +22,7 @@
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/TestUtils.h"
+#include "utils/Color.h"
#include <functional>
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
new file mode 100644
index 0000000..1823db2
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "TestSceneBase.h"
+#include "utils/Color.h"
+
+class TextAnimation;
+
+static TestScene::Registrar _Text(TestScene::Info{
+ "text",
+ "Draws a bunch of text.",
+ TestScene::simpleCreateScene<TextAnimation>
+});
+
+class TextAnimation : public TestScene {
+public:
+ sp<RenderNode> card;
+ void createContent(int width, int height, TestCanvas& canvas) override {
+ canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+ card = TestUtils::createNode(0, 0, width, height,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+
+ paint.setColor(Color::Black);
+ for (int i = 0; i < 10; i++) {
+ TestUtils::drawTextToCanvas(&canvas, "Test string", paint, 400, i * 100);
+ }
+
+ SkPath path;
+ path.addOval(SkRect::MakeLTRB(100, 100, 300, 300));
+
+ paint.setColor(Color::Blue_500);
+ TestUtils::drawTextToCanvas(&canvas, "This is a neat circle of text!", paint, path);
+ });
+ canvas.drawRenderNode(card.get());
+ }
+
+ void doFrame(int frameNr) override {
+ int curFrame = frameNr % 150;
+ card->mutateStagingProperties().setTranslationX(curFrame);
+ card->mutateStagingProperties().setTranslationY(curFrame);
+ card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+ }
+};
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 8261220..a843e92 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -38,6 +38,30 @@
}
};
+template<class T>
+class ModifiedMovingAverage {
+public:
+ ModifiedMovingAverage(int weight) : mWeight(weight) {}
+
+ T add(T today) {
+ if (!mHasValue) {
+ mAverage = today;
+ } else {
+ mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
+ }
+ return mAverage;
+ }
+
+ T average() {
+ return mAverage;
+ }
+
+private:
+ bool mHasValue = false;
+ int mWeight;
+ T mAverage;
+};
+
void run(const TestScene::Info& info, const TestScene::Options& opts) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
@@ -67,22 +91,35 @@
proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
// Do a few cold runs then reset the stats so that the caches are all hot
- for (int i = 0; i < 3; i++) {
+ for (int i = 0; i < 5; i++) {
testContext.waitForVsync();
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
proxy->syncAndDrawFrame();
}
+
proxy->resetProfileInfo();
+ proxy->fence();
+
+ ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
for (int i = 0; i < opts.count; i++) {
testContext.waitForVsync();
-
- ATRACE_NAME("UI-Draw Frame");
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
- UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
- scene->doFrame(i);
- proxy->syncAndDrawFrame();
+ {
+ ATRACE_NAME("UI-Draw Frame");
+ UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
+ scene->doFrame(i);
+ proxy->syncAndDrawFrame();
+ }
+ proxy->fence();
+ nsecs_t done = systemTime(CLOCK_MONOTONIC);
+ if (opts.reportFrametimeWeight) {
+ avgMs.add((done - vsync) / 1000000.0);
+ if (i % 10 == 9) {
+ printf("Average frametime %.3fms\n", avgMs.average());
+ }
+ }
}
proxy->dumpProfileInfo(STDOUT_FILENO, 0);
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 619713c..1616a95 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,6 +17,7 @@
#include "tests/common/TestScene.h"
#include "protos/hwui.pb.h"
+#include "Properties.h"
#include <getopt.h>
#include <stdio.h>
@@ -25,26 +26,38 @@
#include <unordered_map>
#include <vector>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::test;
-static int gFrameCount = 150;
static int gRepeatCount = 1;
static std::vector<TestScene::Info> gRunTests;
+static TestScene::Options gOpts;
void run(const TestScene::Info& info, const TestScene::Options& opts);
static void printHelp() {
- printf("\
-USAGE: hwuitest [OPTIONS] <TESTNAME>\n\
-\n\
-OPTIONS:\n\
- -c, --count=NUM NUM loops a test should run (example, number of frames)\n\
- -r, --runs=NUM Repeat the test(s) NUM times\n\
- -h, --help Display this help\n\
- --list List all tests\n\
-\n");
+ printf(R"(
+USAGE: hwuitest [OPTIONS] <TESTNAME>
+
+OPTIONS:
+ -c, --count=NUM NUM loops a test should run (example, number of frames)
+ -r, --runs=NUM Repeat the test(s) NUM times
+ -h, --help Display this help
+ --list List all tests
+ --wait-for-gpu Set this to wait for the GPU before producing the
+ next frame. Note that without locked clocks this will
+ pathologically bad performance due to large idle time
+ --report-frametime[=weight] If set, the test will print to stdout the
+ moving average frametime. Weight is optional, default is 10
+ --cpuset=name Adds the test to the specified cpuset before running
+ Not supported on all devices and needs root
+)");
}
static void listTests() {
@@ -77,11 +90,56 @@
}
}
+static void moveToCpuSet(const char* cpusetName) {
+ if (access("/dev/cpuset/tasks", F_OK)) {
+ fprintf(stderr, "don't have access to cpusets, skipping...\n");
+ return;
+ }
+ static const int BUF_SIZE = 100;
+ char buffer[BUF_SIZE];
+
+ if (snprintf(buffer, BUF_SIZE, "/dev/cpuset/%s/tasks", cpusetName) >= BUF_SIZE) {
+ fprintf(stderr, "Error, cpusetName too large to fit in buffer '%s'\n", cpusetName);
+ return;
+ }
+ int fd = open(buffer, O_WRONLY | O_CLOEXEC);
+ if (fd == -1) {
+ fprintf(stderr, "Error opening file %d\n", errno);
+ return;
+ }
+ pid_t pid = getpid();
+
+ int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+ if (towrite >= BUF_SIZE) {
+ fprintf(stderr, "Buffer wasn't large enough?\n");
+ } else {
+ if (write(fd, buffer, towrite) != towrite) {
+ fprintf(stderr, "Failed to write, errno=%d", errno);
+ }
+ }
+ close(fd);
+}
+
+// For options that only exist in long-form. Anything in the
+// 0-255 range is reserved for short options (which just use their ASCII value)
+namespace LongOpts {
+enum {
+ Reserved = 255,
+ List,
+ WaitForGpu,
+ ReportFrametime,
+ CpuSet,
+};
+}
+
static const struct option LONG_OPTIONS[] = {
{ "frames", required_argument, nullptr, 'f' },
{ "repeat", required_argument, nullptr, 'r' },
{ "help", no_argument, nullptr, 'h' },
- { "list", no_argument, nullptr, 'l' },
+ { "list", no_argument, nullptr, LongOpts::List },
+ { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
+ { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
+ { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
{ 0, 0, 0, 0 }
};
@@ -89,8 +147,6 @@
void parseOptions(int argc, char* argv[]) {
int c;
- // temporary variable
- int count;
bool error = false;
opterr = 0;
@@ -110,31 +166,53 @@
// (although none of the current LONG_OPTIONS do this...)
break;
- case 'l':
+ case LongOpts::List:
listTests();
exit(EXIT_SUCCESS);
break;
case 'c':
- count = atoi(optarg);
- if (!count) {
+ gOpts.count = atoi(optarg);
+ if (!gOpts.count) {
fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
error = true;
- } else {
- gFrameCount = (count > 0 ? count : INT_MAX);
}
break;
case 'r':
- count = atoi(optarg);
- if (!count) {
+ gRepeatCount = atoi(optarg);
+ if (!gRepeatCount) {
fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
error = true;
} else {
- gRepeatCount = (count > 0 ? count : INT_MAX);
+ gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
}
break;
+ case LongOpts::ReportFrametime:
+ if (optarg) {
+ gOpts.reportFrametimeWeight = atoi(optarg);
+ if (!gOpts.reportFrametimeWeight) {
+ fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ error = true;
+ }
+ } else {
+ gOpts.reportFrametimeWeight = 10;
+ }
+ break;
+
+ case LongOpts::WaitForGpu:
+ Properties::waitForGpuCompletion = true;
+ break;
+
+ case LongOpts::CpuSet:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ moveToCpuSet(optarg);
+ break;
+
case 'h':
printHelp();
exit(EXIT_SUCCESS);
@@ -172,13 +250,14 @@
}
int main(int argc, char* argv[]) {
+ // set defaults
+ gOpts.count = 150;
+
parseOptions(argc, argv);
- TestScene::Options opts;
- opts.count = gFrameCount;
for (int i = 0; i < gRepeatCount; i++) {
for (auto&& test : gRunTests) {
- run(test, opts);
+ run(test, gOpts);
}
}
printf("Success!\n");
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 3d9fafa..bd742c6 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -17,7 +17,7 @@
#include <benchmark/Benchmark.h>
#include "PathParser.h"
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include <SkPath.h>
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
new file mode 100755
index 0000000..09d4869
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+adb root
+adb wait-for-device
+adb shell stop mpdecision
+adb shell stop perfd
+adb shell stop
+for pid in $( adb shell ps | awk '{ if ( $9 == "surfaceflinger" ) { print $2 } }' ); do
+ adb shell kill $pid
+done
+adb shell setprop debug.egl.traceGpuCompletion 1
+adb shell daemonize surfaceflinger
+sleep 3
+adb shell setprop service.bootanim.exit 1
+
+# cpu possible frequencies
+# 204000 229500 255000 280500 306000 331500 357000 382500 408000 433500 459000
+# 484500 510000 535500 561000 586500 612000 637500 663000 688500 714000 739500
+# 765000 790500 816000 841500 867000 892500 918000 943500 969000 994500 1020000
+# 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1938000
+# 2014500 2091000 2193000 2295000 2397000 2499000
+
+S=1326000
+echo "set cpu $cpu to $S hz";
+adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+
+#disable hotplug
+adb shell "echo 0 > /sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable"
+
+# gbus possible rates
+# 72000 108000 180000 252000 324000 396000 468000 540000 612000 648000
+# 684000 708000 756000 804000 852000 (kHz)
+
+S=324000000
+echo "set gpu to $s hz"
+adb shell "echo 1 > /d/clock/override.gbus/state"
+adb shell "echo $S > /d/clock/override.gbus/rate"
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index 8321ff9..3fd822d 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <BakedOpState.h>
+#include <ClipArea.h>
#include <RecordedOp.h>
#include <tests/common/TestUtils.h>
@@ -24,31 +25,33 @@
namespace uirenderer {
TEST(ResolvedRenderState, construct) {
+ LinearAllocator allocator;
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
SkPaint paint;
- RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
+ ClipRect clip(Rect(100, 200));
+ RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint);
{
// recorded with transform, no parent transform
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
- EXPECT_EQ(Rect(0, 0, 100, 200), state.clipRect);
+ EXPECT_EQ(Rect(100, 200), state.clipRect());
EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
}
{
// recorded with transform and parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Matrix4 expectedTranslate;
expectedTranslate.loadTranslate(20, 40, 0);
EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
// intersection of parent & transformed child clip
- EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
+ EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect());
// translated and also clipped
EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
@@ -56,6 +59,30 @@
}
}
+TEST(ResolvedRenderState, computeLocalSpaceClip) {
+ LinearAllocator allocator;
+ Matrix4 translate10x20;
+ translate10x20.loadTranslate(10, 20, 0);
+
+ SkPaint paint;
+ ClipRect clip(Rect(100, 200));
+ RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint);
+ {
+ // recorded with transform, no parent transform
+ auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
+ << "Local clip rect should be 100x200, offset by -10,-20";
+ }
+ {
+ // recorded with transform + parent transform
+ auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
+ EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
+ << "Local clip rect should be 90x190, offset by -10,-20";
+ }
+}
+
const float HAIRLINE = 0.0f;
// Note: bounds will be conservative, but not precise for non-hairline
@@ -127,6 +154,7 @@
};
TEST(ResolvedRenderState, construct_expandForStroke) {
+ LinearAllocator allocator;
// Loop over table of test cases and verify different combinations of stroke width and transform
for (auto&& testCase : sStrokeTestCases) {
SkPaint strokedPaint;
@@ -134,14 +162,15 @@
strokedPaint.setStyle(SkPaint::kStroke_Style);
strokedPaint.setStrokeWidth(testCase.strokeWidth);
+ ClipRect clip(Rect(200, 200));
RectOp recordedOp(Rect(50, 50, 150, 150),
- Matrix4::identity(), Rect(200, 200), &strokedPaint);
+ Matrix4::identity(), &clip, &strokedPaint);
Matrix4 snapshotMatrix;
snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
- ResolvedRenderState state(*parentSnapshot, recordedOp, true);
+ ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
testCase.validator(state);
}
}
@@ -153,8 +182,9 @@
translate100x0.loadTranslate(100, 0, 0);
SkPaint paint;
+ ClipRect clip(Rect(100, 200));
{
- RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
+ RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
@@ -162,7 +192,7 @@
EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
}
{
- RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+ RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
@@ -196,7 +226,8 @@
SkPaint paint;
paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(0.0f);
- RectOp rejectOp(Rect(0, 0, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+ ClipRect clip(Rect(100, 200));
+ RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::StyleDefined);
@@ -209,7 +240,8 @@
SkPaint paint;
paint.setStyle(SkPaint::kStrokeAndFill_Style);
paint.setStrokeWidth(10.0f);
- RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+ ClipRect clip(Rect(200, 200));
+ RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::StyleDefined);
@@ -223,7 +255,8 @@
SkPaint paint;
paint.setStyle(SkPaint::kFill_Style);
paint.setStrokeWidth(10.0f);
- RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+ ClipRect clip(Rect(200, 200));
+ RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
BakedOpState::StrokeBehavior::Forced);
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index dfbf6d3..4df2687 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -57,7 +57,7 @@
simpleTranslate.loadTranslate(10, 20, 0);
state.setMatrix(simpleTranslate);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200));
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200));
ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
EXPECT_TRUE(state.clipIsSimple());
@@ -69,7 +69,7 @@
0, 0, 200, 200, Vector3());
state.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 100, 100));
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
state.clipRect(10, 10, 200, 200, SkRegion::kIntersect_Op);
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
@@ -122,10 +122,10 @@
state.save(SkCanvas::kClip_SaveFlag);
{
state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200)); // verify restore
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
@@ -146,10 +146,10 @@
state.save(SkCanvas::kMatrix_SaveFlag); // NOTE: clip not saved
{
state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10)); // verify not restored
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index c4d305e..4cae737 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -119,5 +119,122 @@
EXPECT_EQ(expected, area.getClipRect());
}
+TEST(ClipArea, serializeClip) {
+ ClipArea area(createClipArea());
+ LinearAllocator allocator;
+
+ // unset clip
+ EXPECT_EQ(nullptr, area.serializeClip(allocator));
+
+ // rect clip
+ area.setClip(0, 0, 200, 200);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, serializedClip);
+ ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
+ auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip);
+ ASSERT_EQ(Rect(200, 200), clipRect->rect);
+ EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
+
+ // rect list
+ Matrix4 rotate;
+ rotate.loadRotate(2.0f);
+ area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, serializedClip);
+ ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
+ auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
+ ASSERT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
+
+ // region
+ SkPath circlePath;
+ circlePath.addCircle(100, 100, 100);
+ area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+ {
+ auto serializedClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, serializedClip);
+ ASSERT_EQ(ClipMode::Region, serializedClip->mode);
+ auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
+ ASSERT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
+ << "Clip region should be 200x200";
+ EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+ << "Requery of clip on unmodified ClipArea must return same pointer.";
+ }
}
+
+TEST(ClipArea, serializeIntersectedClip) {
+ ClipArea area(createClipArea());
+ LinearAllocator allocator;
+
+ // simple state;
+ EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ area.setClip(0, 0, 200, 200);
+ {
+ auto origRectClip = area.serializeClip(allocator);
+ ASSERT_NE(nullptr, origRectClip);
+ EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ }
+
+ // rect
+ {
+ ClipRect recordedClip(Rect(100, 100));
+ Matrix4 translateScale;
+ translateScale.loadTranslate(100, 100, 0);
+ translateScale.scale(2, 3, 1);
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+ EXPECT_EQ(Rect(100, 100, 200, 200),
+ reinterpret_cast<const ClipRect*>(resolvedClip)->rect);
+
+ EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+ << "Must return previous serialization, since input is same";
+
+ ClipRect recordedClip2(Rect(100, 100));
+ EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+ << "Shouldn't return previous serialization, since matrix location is different";
+ }
+
+ // rect list
+ Matrix4 rotate;
+ rotate.loadRotate(2.0f);
+ area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+ {
+ ClipRect recordedClip(Rect(100, 100));
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
+ auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
+ EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+ }
+
+ // region
+ SkPath circlePath;
+ circlePath.addCircle(100, 100, 100);
+ area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+ {
+ SkPath ovalPath;
+ ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
+
+ ClipRegion recordedClip;
+ recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+
+ Matrix4 translate10x20;
+ translate10x20.loadTranslate(10, 20, 0);
+ auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
+ translate10x20); // Note: only translate for now, others not handled correctly
+ ASSERT_NE(nullptr, resolvedClip);
+ ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
+ auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
+ EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
+ }
}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 78d65dd..5c4429010 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -27,7 +27,7 @@
int two = 2;
};
-TEST(LinearAllocator, alloc) {
+TEST(LinearAllocator, create) {
LinearAllocator la;
EXPECT_EQ(0u, la.usedSize());
la.alloc(64);
@@ -35,7 +35,7 @@
// so the usedSize isn't strictly defined
EXPECT_LE(64u, la.usedSize());
EXPECT_GT(80u, la.usedSize());
- auto pair = la.alloc<SimplePair>();
+ auto pair = la.create<SimplePair>();
EXPECT_LE(64u + sizeof(SimplePair), la.usedSize());
EXPECT_GT(80u + sizeof(SimplePair), la.usedSize());
EXPECT_EQ(1, pair->one);
@@ -47,8 +47,8 @@
{
LinearAllocator la;
for (int i = 0; i < 5; i++) {
- la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
- la.alloc<SimplePair>();
+ la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
+ la.create<SimplePair>();
}
la.alloc(100);
for (int i = 0; i < 5; i++) {
@@ -75,7 +75,7 @@
la.rewindIfLastAlloc(addr, 100);
EXPECT_GT(16u, la.usedSize());
size_t emptySize = la.usedSize();
- auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
+ auto sigdtor = la.create<TestUtils::SignalingDtor>();
sigdtor->setSignal(&destroyed);
EXPECT_EQ(0, destroyed);
EXPECT_LE(emptySize, la.usedSize());
diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp
index 5eac498..66dccb4 100644
--- a/libs/hwui/tests/unit/OpReordererTests.cpp
+++ b/libs/hwui/tests/unit/OpReordererTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <BakedOpState.h>
+#include <DeferredLayerUpdater.h>
#include <LayerUpdateQueue.h>
#include <OpReorderer.h>
#include <RecordedOp.h>
@@ -63,14 +64,14 @@
ADD_FAILURE() << "Layer updates not expected in this test";
}
virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
- virtual void endFrame() {}
+ virtual void endFrame(const Rect& repaintRect) {}
// define virtual defaults for single draw methods
#define X(Type) \
virtual void on##Type(const Type&, const BakedOpState&) { \
ADD_FAILURE() << #Type " not expected in this test"; \
}
- MAP_OPS(X)
+ MAP_RENDERABLE_OPS(X)
#undef X
// define virtual defaults for merged draw methods
@@ -78,7 +79,7 @@
virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
}
- MAP_MERGED_OPS(X)
+ MAP_MERGEABLE_OPS(X)
#undef X
int getIndex() { return mIndex; }
@@ -98,7 +99,7 @@
static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
renderer.on##Type(op, state); \
}
- MAP_OPS(X);
+ MAP_RENDERABLE_OPS(X);
#undef X
// define merged op methods, which redirect to TestRendererBase
@@ -106,7 +107,7 @@
static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
renderer.onMerged##Type##s(opList); \
}
- MAP_MERGED_OPS(X);
+ MAP_MERGEABLE_OPS(X);
#undef X
};
@@ -126,7 +127,7 @@
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(3, mIndex++);
}
};
@@ -221,7 +222,75 @@
<< "Expect number of ops = 2 * loop count";
}
-TEST(OpReorderer, textStrikethroughBatching) {
+TEST(OpReorderer, clippedMerging) {
+ class ClippedMergingTestRenderer : public TestRendererBase {
+ public:
+ void onMergedBitmapOps(const MergedBakedOpList& opList) override {
+ EXPECT_EQ(0, mIndex);
+ mIndex += opList.count;
+ EXPECT_EQ(4u, opList.count);
+ EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
+ EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
+ opList.clipSideFlags);
+ }
+ };
+ auto node = TestUtils::createNode(0, 0, 100, 100,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ SkBitmap bitmap = TestUtils::createSkBitmap(20, 20);
+
+ // left side clipped (to inset left half)
+ canvas.clipRect(10, 0, 50, 100, SkRegion::kReplace_Op);
+ canvas.drawBitmap(bitmap, 0, 40, nullptr);
+
+ // top side clipped (to inset top half)
+ canvas.clipRect(0, 10, 100, 50, SkRegion::kReplace_Op);
+ canvas.drawBitmap(bitmap, 40, 0, nullptr);
+
+ // right side clipped (to inset right half)
+ canvas.clipRect(50, 0, 90, 100, SkRegion::kReplace_Op);
+ canvas.drawBitmap(bitmap, 80, 40, nullptr);
+
+ // bottom not clipped, just abutting (inset bottom half)
+ canvas.clipRect(0, 50, 100, 90, SkRegion::kReplace_Op);
+ canvas.drawBitmap(bitmap, 40, 70, nullptr);
+ });
+
+ OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ createSyncedNodeList(node), sLightCenter);
+ ClippedMergingTestRenderer renderer;
+ reorderer.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(4, renderer.getIndex());
+}
+
+TEST(OpReorderer, textMerging) {
+ class TextMergingTestRenderer : public TestRendererBase {
+ public:
+ void onMergedTextOps(const MergedBakedOpList& opList) override {
+ EXPECT_EQ(0, mIndex);
+ mIndex += opList.count;
+ EXPECT_EQ(2u, opList.count);
+ EXPECT_EQ(OpClipSideFlags::Top, opList.clipSideFlags);
+ EXPECT_EQ(OpClipSideFlags::Top, opList.states[0]->computedState.clipSideFlags);
+ EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
+ }
+ };
+ auto node = TestUtils::createNode(0, 0, 400, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
+ TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
+ });
+ OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+ createSyncedNodeList(node), sLightCenter);
+ TextMergingTestRenderer renderer;
+ reorderer.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
+}
+
+TEST(OpReorderer, textStrikethrough) {
const int LOOPS = 5;
class TextStrikethroughTestRenderer : public TestRendererBase {
public:
@@ -250,7 +319,40 @@
TextStrikethroughTestRenderer renderer;
reorderer.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2 * LOOPS, renderer.getIndex())
- << "Expect number of ops = 2 * loop count"; // TODO: force no merging
+ << "Expect number of ops = 2 * loop count";
+}
+
+RENDERTHREAD_TEST(OpReorderer, textureLayer) {
+ class TextureLayerTestRenderer : public TestRendererBase {
+ public:
+ void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
+ EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
+
+ Matrix4 expected;
+ expected.loadTranslate(5, 5, 0);
+ EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform);
+ }
+ };
+
+ auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
+ [](Matrix4* transform) {
+ transform->loadTranslate(5, 5, 0);
+ });
+
+ auto node = TestUtils::createNode(0, 0, 200, 200,
+ [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ canvas.clipRect(50, 50, 150, 150, SkRegion::kIntersect_Op);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
+ OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
+ createSyncedNodeList(node), sLightCenter);
+ TextureLayerTestRenderer renderer;
+ reorderer.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(1, renderer.getIndex());
}
TEST(OpReorderer, renderNode) {
@@ -259,7 +361,7 @@
void onRectOp(const RectOp& op, const BakedOpState& state) override {
switch(mIndex++) {
case 0:
- EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
break;
case 1:
@@ -279,16 +381,15 @@
canvas.drawRect(0, 0, 100, 100, paint);
});
- RenderNode* childPtr = child.get();
auto parent = TestUtils::createNode(0, 0, 200, 200,
- [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
+ [&child](RenderProperties& props, RecordingCanvas& canvas) {
SkPaint paint;
paint.setColor(SK_ColorDKGRAY);
canvas.drawRect(0, 0, 200, 200, paint);
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
canvas.translate(40, 40);
- canvas.drawRenderNode(childPtr);
+ canvas.drawRenderNode(child.get());
canvas.restore();
});
@@ -304,7 +405,7 @@
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(0, mIndex++);
EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+ EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
@@ -337,8 +438,8 @@
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
- EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
+ EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
+ EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
Matrix4 expectedTransform;
expectedTransform.loadTranslate(-10, -10, 0);
@@ -347,7 +448,7 @@
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
- EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
+ EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
@@ -393,25 +494,25 @@
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(7, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(9, mIndex++);
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 1) {
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
} else if (index == 4) {
- EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
} else { ADD_FAILURE(); }
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 5) {
EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
} else if (index == 8) {
EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
- EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
} else { ADD_FAILURE(); }
}
};
@@ -473,7 +574,7 @@
EXPECT_TRUE(state.computedState.transform.isIdentity())
<< "Transform should be reset within layer";
- EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
+ EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
void endLayer() override {
@@ -485,7 +586,7 @@
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(5, mIndex++);
}
};
@@ -574,7 +675,7 @@
EXPECT_EQ(200u, layer->viewportHeight);
} else { ADD_FAILURE(); }
}
- void endFrame() override {
+ void endFrame(const Rect& repaintRect) override {
EXPECT_EQ(12, mIndex++);
}
};
@@ -1091,7 +1192,7 @@
});
EXPECT_EQ(190u, observedData.layerWidth);
EXPECT_EQ(200u, observedData.layerHeight);
- EXPECT_EQ(Rect(0, 0, 190, 200), observedData.rectClippedBounds)
+ EXPECT_EQ(Rect(190, 200), observedData.rectClippedBounds)
<< "expect content to be clipped to screen area";
Matrix4 expected;
expected.loadTranslate(0, -2000, 0);
@@ -1114,7 +1215,7 @@
// ceil(sqrt(2) / 2 * 200) = 142
EXPECT_EQ(142u, observedData.layerWidth);
EXPECT_EQ(142u, observedData.layerHeight);
- EXPECT_EQ(Rect(0, 0, 142, 142), observedData.rectClippedBounds);
+ EXPECT_EQ(Rect(142, 142), observedData.rectClippedBounds);
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
}
@@ -1128,7 +1229,7 @@
});
EXPECT_EQ(100u, observedData.layerWidth);
EXPECT_EQ(400u, observedData.layerHeight);
- EXPECT_EQ(Rect(0, 0, 100, 400), observedData.rectClippedBounds);
+ EXPECT_EQ(Rect(100, 400), observedData.rectClippedBounds);
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index ba9d185..a63cb18 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -33,6 +33,14 @@
}
}
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+ EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+ if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+ EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+ } else { \
+ ADD_FAILURE() << "ClipState not a rect"; \
+ }
+
TEST(RecordingCanvas, emptyPlayback) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -41,6 +49,22 @@
playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
}
+TEST(RecordingCanvas, clipRect) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
+ canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+ canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawRect(50, 50, 100, 100, SkPaint());
+ canvas.restore();
+ });
+
+ ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops";
+ EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip);
+ EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip);
+ EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip)
+ << "Clip should be serialized once";
+}
+
TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
@@ -54,7 +78,7 @@
ASSERT_EQ(RecordedOpId::LinesOp, op->opId);
EXPECT_EQ(4, ((LinesOp*)op)->floatCount)
<< "float count must be rounded down to closest multiple of 4";
- EXPECT_EQ(Rect(0, 0, 20, 10), op->unmappedBounds)
+ EXPECT_EQ(Rect(20, 10), op->unmappedBounds)
<< "unmapped bounds must be size of line, and not outset for stroke width";
}
@@ -66,7 +90,7 @@
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
ASSERT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
}
@@ -83,7 +107,7 @@
playbackOps(*dl, [&count](const RecordedOp& op) {
count++;
ASSERT_EQ(RecordedOpId::TextOp, op.opId);
- EXPECT_EQ(Rect(0, 0, 200, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_TRUE(op.localMatrix.isIdentity());
EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
<< "Op expected to be 25+ pixels wide, 10+ pixels tall";
@@ -184,8 +208,8 @@
ASSERT_EQ(RecordedOpId::RectOp, op.opId);
ASSERT_NE(nullptr, op.paint);
EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
- EXPECT_EQ(Rect(0, 0, 100, 200), op.unmappedBounds);
- EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+ EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
Matrix4 expectedMatrix;
expectedMatrix.loadIdentity();
@@ -193,8 +217,8 @@
} else {
ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
EXPECT_EQ(nullptr, op.paint);
- EXPECT_EQ(Rect(0, 0, 25, 25), op.unmappedBounds);
- EXPECT_EQ(Rect(0, 0, 100, 200), op.localClipRect);
+ EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
Matrix4 expectedMatrix;
expectedMatrix.loadTranslate(25, 25, 0);
@@ -219,12 +243,12 @@
case 0:
EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(Rect(0, 0, 200, 200), op.localClipRect);
+ EXPECT_EQ(nullptr, op.localClip);
EXPECT_TRUE(op.localMatrix.isIdentity());
break;
case 1:
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(0, 0, 180, 160), op.localClipRect);
+ EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
expectedMatrix.loadTranslate(-10, -20, 0);
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -254,9 +278,9 @@
if (count++ == 1) {
Matrix4 expectedMatrix;
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect) << "Recorded clip rect should be"
- " intersection of viewport and saveLayer bounds, in layer space";
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+ // intersection of viewport and saveLayer bounds, in layer space;
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadTranslate(-100, -100, 0);
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
}
@@ -281,8 +305,8 @@
playbackOps(*dl, [&count](const RecordedOp& op) {
if (count++ == 1) {
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(Rect(0, 0, 100, 100), op.localClipRect);
- EXPECT_EQ(Rect(0, 0, 100, 100), op.unmappedBounds);
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
+ EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
<< "Recorded op shouldn't see any canvas transform before the saveLayer";
}
@@ -312,8 +336,17 @@
// ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
// the parent 200x200 viewport, but prior to rotation
- EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
- EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds);
+ ASSERT_NE(nullptr, op.localClip);
+ ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
+ // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
+ // causes the clip to be recorded by contained draw commands, though it's not necessary
+ // since the same clip will be computed at draw time. If such a change is made, this
+ // check could be done at record time by querying the clip, or the clip could be altered
+ // slightly so that it is serialized.
+ EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
+ (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
+
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadIdentity();
EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 77dd73a..7208547 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "PathParser.h"
+#include "VectorDrawable.h"
#include "utils/MathUtils.h"
#include "utils/VectorDrawableUtils.h"
@@ -98,6 +99,65 @@
}
},
+ // Check box VectorDrawable path data
+ {
+ // Path
+ "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
+ {
+ {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
+ {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0, 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0, -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(0.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
+ outPath->close();
+ outPath->moveTo(0.0, -1.0);
+ outPath->moveTo(7.0, -9.0);
+ outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
+ outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
+ outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
+ outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
+ outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ outPath->close();
+ outPath->moveTo(7.0, -9.0);
+ }
+ },
+
+ // pie1 in progress bar
+ {
+ "M300,70 a230,230 0 1,0 1,0 z",
+ {
+ {'M', 'a', 'z', },
+ {2, 7, 0, },
+ {300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0, },
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(300.0, 70.0);
+ outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267, 94.47383115953485, 137.6004913602211, 137.6302781499585);
+ outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275, 239.3163266242308, 70.50013586976587, 300.2494566687817);
+ outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249, 419.65954850554147, 137.9538527586204, 462.72238058830936);
+ outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056, 529.999456521097, 300.49999999999994, 529.999456521097);
+ outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176, 505.78521267107726, 463.0461472413797, 462.7223805883093);
+ outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891, 361.1825867133324, 530.4998641302341, 300.2494566687815);
+ outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844, 180.7867251403819, 463.3995086397787, 137.6302781499583);
+ outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255, 70.13246340443492, 300.9999999999996, 70.00000000000003);
+ outPath->close();
+ outPath->moveTo(300.0, 70.0);
+ }
+ },
+
// Random long data
{
// Path
@@ -178,6 +238,7 @@
{"1-2e34567", false}
};
+
static bool hasSameVerbs(const PathData& from, const PathData& to) {
return from.verbs == to.verbs && from.verbSizes == to.verbSizes;
}
@@ -284,6 +345,49 @@
}
}
+TEST(VectorDrawable, matrixScale) {
+ struct MatrixAndScale {
+ float buffer[9];
+ float matrixScale;
+ };
+ const MatrixAndScale sMatrixAndScales[] {
+ {
+ {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ 1.0
+ },
+ {
+ {1.0f, 0.0f, 240.0f, 0.0f, 1.0f, 240.0f, 0.0f, 0.0f, 1.0f},
+ 1.0f,
+ },
+ {
+ {1.5f, 0.0f, 24.0f, 0.0f, 1.5f, 24.0f, 0.0f, 0.0f, 1.0f},
+ 1.5f,
+ },
+ {
+ {0.99999994f, 0.0f, 300.0f, 0.0f, 0.99999994f, 158.57864f, 0.0f, 0.0f, 1.0f},
+ 0.99999994f,
+ },
+ {
+ {0.7071067f, 0.7071067f, 402.5305f, -0.7071067f, 0.7071067f, 169.18524f, 0.0f, 0.0f, 1.0f},
+ 0.99999994f,
+ },
+ {
+ {0.0f, 0.9999999f, 482.5305f, -0.9999999f, 0.0f, 104.18525f, 0.0f, 0.0f, 1.0f},
+ 0.9999999f,
+ },
+ {
+ {-0.35810637f, -0.93368083f, 76.55821f, 0.93368083f, -0.35810637f, 89.538506f, 0.0f, 0.0f, 1.0f},
+ 1.0000001f,
+ },
+ };
+
+ for (MatrixAndScale matrixAndScale : sMatrixAndScales) {
+ SkMatrix matrix;
+ matrix.set9(matrixAndScale.buffer);
+ float actualMatrixScale = VectorDrawable::Path::getMatrixScale(matrix);
+ EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
+ }
+}
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index e1c6f6c..dcbc0dd 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,12 +56,12 @@
void* alloc(size_t size);
/**
- * Allocates an instance of the template type with the default constructor
+ * Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
- template<class T>
- T* alloc() {
- T* ret = new (*this) T;
+ template<class T, typename... Params>
+ T* create(Params... params) {
+ T* ret = new (*this) T(params...);
autoDestroy(ret);
return ret;
}
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index 21c1cdc..b5ef510 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -17,7 +17,7 @@
#ifndef ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
#define ANDROID_HWUI_VECTORDRAWABLE_UTILS_H
-#include "VectorDrawablePath.h"
+#include "VectorDrawable.h"
#include <cutils/compiler.h>
#include "SkPath.h"
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 529849e..212c6a0 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -90,6 +90,7 @@
mLocked.lastFrameUpdatedTime = 0;
mLocked.buttonState = 0;
+ mLocked.iconDetached = false;
mPolicy->loadPointerIcon(&mLocked.pointerIcon);
@@ -184,6 +185,10 @@
}
void PointerController::setPositionLocked(float x, float y) {
+ if (mLocked.iconDetached) {
+ return;
+ }
+
float minX, minY, maxX, maxY;
if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) {
if (x <= minX) {
@@ -217,6 +222,10 @@
// Remove the inactivity timeout, since we are fading now.
removeInactivityTimeoutLocked();
+ if (mLocked.iconDetached) {
+ return;
+ }
+
// Start fading.
if (transition == TRANSITION_IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
@@ -234,6 +243,10 @@
// Always reset the inactivity timer.
resetInactivityTimeoutLocked();
+ if (mLocked.iconDetached) {
+ return;
+ }
+
// Start unfading.
if (transition == TRANSITION_IMMEDIATE) {
mLocked.pointerFadeDirection = 0;
@@ -349,6 +362,22 @@
updatePointerLocked();
}
+void PointerController::detachPointerIcon(bool detached) {
+ AutoMutex _l(mLock);
+
+ if (mLocked.iconDetached == detached) {
+ return;
+ }
+
+ mLocked.iconDetached = detached;
+ if (detached) {
+ mLocked.pointerFadeDirection = -1;
+ } else {
+ mLocked.pointerFadeDirection = 1;
+ }
+ startAnimationLocked();
+}
+
void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) {
AutoMutex _l(mLock);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 9ba37b3..c1381f3 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -111,6 +111,10 @@
void setInactivityTimeout(InactivityTimeout inactivityTimeout);
void reloadPointerResources();
+ /* Detach or attach the pointer icon status. When detached, the pointer icon disappears
+ * and the icon location does not change at all. */
+ void detachPointerIcon(bool detached);
+
private:
static const size_t MAX_RECYCLED_SPRITES = 12;
static const size_t MAX_SPOTS = 12;
@@ -180,6 +184,8 @@
int32_t buttonState;
+ bool iconDetached;
+
Vector<Spot*> spots;
Vector<sp<Sprite> > recycledSprites;
} mLocked;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index bb4f7d9..6dd1072 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -97,9 +97,10 @@
/** Maximum value for sample rate */
private static final int SAMPLE_RATE_HZ_MAX = 192000;
- // FCC_8
- /** Maximum value for AudioTrack channel count */
- private static final int CHANNEL_COUNT_MAX = 8;
+ /** Maximum value for AudioTrack channel count
+ * @hide public for MediaCode only, do not un-hide or change to a numeric literal
+ */
+ public static final int CHANNEL_COUNT_MAX = 8; // FIXME was native_get_FCC_8(), unregistered!
/** indicates AudioTrack state is stopped */
public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED
@@ -2583,6 +2584,7 @@
private native final int native_getRoutedDeviceId();
private native final void native_enableDeviceCallback();
private native final void native_disableDeviceCallback();
+ // FIXME static private native int native_get_FCC_8();
//---------------------------------------------------------
// Utility methods
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index e6bc8f1..9bcb5e3 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -907,7 +907,7 @@
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) {
sampleRateRange = Range.create(1, 96000);
bitRates = Range.create(1, 10000000);
- maxChannels = 8;
+ maxChannels = AudioTrack.CHANNEL_COUNT_MAX;
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
sampleRateRange = Range.create(1, 655350);
// lossless codec, so bitrate is ignored
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 41b369d..dd06921 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -16,8 +16,8 @@
package android.media;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
-import android.content.IContentProvider;
import android.net.Uri;
import android.os.RemoteException;
@@ -37,13 +37,11 @@
private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
new HashMap<Uri, List<ContentValues>>();
- private final IContentProvider mProvider;
- private final String mPackageName;
+ private final ContentProviderClient mProvider;
private final int mBufferSizePerUri;
- public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) {
+ public MediaInserter(ContentProviderClient provider, int bufferSizePerUri) {
mProvider = provider;
- mPackageName = packageName;
mBufferSizePerUri = bufferSizePerUri;
}
@@ -90,7 +88,7 @@
if (!list.isEmpty()) {
ContentValues[] valuesArray = new ContentValues[list.size()];
valuesArray = list.toArray(valuesArray);
- mProvider.bulkInsert(mPackageName, tableUri, valuesArray);
+ mProvider.bulkInsert(tableUri, valuesArray);
list.clear();
}
}
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9ea6722..96c616b 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,14 +16,10 @@
package android.media;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
+import android.content.ContentProviderClient;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.IContentProvider;
import android.database.Cursor;
import android.database.SQLException;
import android.drm.DrmManagerClient;
@@ -50,6 +46,12 @@
import android.util.Log;
import android.util.Xml;
+import dalvik.system.CloseGuard;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
import java.io.BufferedReader;
import java.io.File;
import java.io.FileDescriptor;
@@ -61,6 +63,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Internal service helper that no-one should use directly.
@@ -107,8 +110,7 @@
*
* {@hide}
*/
-public class MediaScanner
-{
+public class MediaScanner implements AutoCloseable {
static {
System.loadLibrary("media_jni");
native_init();
@@ -302,21 +304,23 @@
};
private long mNativeContext;
- private Context mContext;
- private String mPackageName;
- private IContentProvider mMediaProvider;
- private Uri mAudioUri;
- private Uri mVideoUri;
- private Uri mImagesUri;
- private Uri mThumbsUri;
- private Uri mPlaylistsUri;
- private Uri mFilesUri;
- private Uri mFilesUriNoNotify;
- private boolean mProcessPlaylists, mProcessGenres;
+ private final Context mContext;
+ private final String mPackageName;
+ private final String mVolumeName;
+ private final ContentProviderClient mMediaProvider;
+ private final Uri mAudioUri;
+ private final Uri mVideoUri;
+ private final Uri mImagesUri;
+ private final Uri mThumbsUri;
+ private final Uri mPlaylistsUri;
+ private final Uri mFilesUri;
+ private final Uri mFilesUriNoNotify;
+ private final boolean mProcessPlaylists;
+ private final boolean mProcessGenres;
private int mMtpObjectHandle;
- private final String mExternalStoragePath;
- private final boolean mExternalIsEmulated;
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
/** whether to use bulk inserts or individual inserts for each item */
private static final boolean ENABLE_BULK_INSERTS = true;
@@ -345,10 +349,6 @@
*/
private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
- // set to true if file path comparisons should be case insensitive.
- // this should be set when scanning files on a case insensitive file system.
- private boolean mCaseInsensitivePaths;
-
private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
private static class FileEntry {
@@ -378,26 +378,59 @@
int bestmatchlevel;
}
- private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
+ private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>();
+ private final ArrayList<FileEntry> mPlayLists = new ArrayList<>();
private MediaInserter mMediaInserter;
- private ArrayList<FileEntry> mPlayLists;
-
private DrmManagerClient mDrmManagerClient = null;
- public MediaScanner(Context c) {
+ public MediaScanner(Context c, String volumeName) {
native_setup();
mContext = c;
mPackageName = c.getPackageName();
+ mVolumeName = volumeName;
+
mBitmapOptions.inSampleSize = 1;
mBitmapOptions.inJustDecodeBounds = true;
setDefaultRingtoneFileNames();
- mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
- mExternalIsEmulated = Environment.isExternalStorageEmulated();
- //mClient.testGenreNameConverter();
+ mMediaProvider = mContext.getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY);
+
+ mAudioUri = Audio.Media.getContentUri(volumeName);
+ mVideoUri = Video.Media.getContentUri(volumeName);
+ mImagesUri = Images.Media.getContentUri(volumeName);
+ mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
+ mFilesUri = Files.getContentUri(volumeName);
+ mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+
+ if (!volumeName.equals("internal")) {
+ // we only support playlists on external media
+ mProcessPlaylists = true;
+ mProcessGenres = true;
+ mPlaylistsUri = Playlists.getContentUri(volumeName);
+ } else {
+ mProcessPlaylists = false;
+ mProcessGenres = false;
+ mPlaylistsUri = null;
+ }
+
+ final Locale locale = mContext.getResources().getConfiguration().locale;
+ if (locale != null) {
+ String language = locale.getLanguage();
+ String country = locale.getCountry();
+ if (language != null) {
+ if (country != null) {
+ setLocale(language + "_" + country);
+ } else {
+ setLocale(language);
+ }
+ }
+ }
+
+ mCloseGuard.open("close");
}
private void setDefaultRingtoneFileNames() {
@@ -956,7 +989,7 @@
if (inserter != null) {
inserter.flushAll();
}
- result = mMediaProvider.insert(mPackageName, tableUri, values);
+ result = mMediaProvider.insert(tableUri, values);
} else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
inserter.insertwithPriority(tableUri, values);
} else {
@@ -988,7 +1021,7 @@
}
values.put(FileColumns.MEDIA_TYPE, mediaType);
}
- mMediaProvider.update(mPackageName, result, values, null, null);
+ mMediaProvider.update(result, values, null, null);
}
if(needToSetSettings) {
@@ -1055,11 +1088,7 @@
String where = null;
String[] selectionArgs = null;
- if (mPlayLists == null) {
- mPlayLists = new ArrayList<FileEntry>();
- } else {
- mPlayLists.clear();
- }
+ mPlayLists.clear();
if (filePath != null) {
// query for only one file
@@ -1077,8 +1106,7 @@
// filesystem is mounted and unmounted while the scanner is running).
Uri.Builder builder = mFilesUri.buildUpon();
builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
- MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
- builder.build());
+ MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
// Build the list of files from the content provider
try {
@@ -1097,7 +1125,7 @@
c.close();
c = null;
}
- c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION,
where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
if (c == null) {
break;
@@ -1138,8 +1166,7 @@
if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
deleter.flush();
String parent = new File(path).getParent();
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
- parent, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null);
}
}
}
@@ -1157,7 +1184,7 @@
// compute original size of images
mOriginalCount = 0;
- c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
if (c != null) {
mOriginalCount = c.getCount();
c.close();
@@ -1189,7 +1216,6 @@
try {
c = mMediaProvider.query(
- mPackageName,
mThumbsUri,
new String [] { "_data" },
null,
@@ -1225,13 +1251,11 @@
static class MediaBulkDeleter {
StringBuilder whereClause = new StringBuilder();
ArrayList<String> whereArgs = new ArrayList<String>(100);
- final IContentProvider mProvider;
- final String mPackageName;
+ final ContentProviderClient mProvider;
final Uri mBaseUri;
- public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
+ public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) {
mProvider = provider;
- mPackageName = packageName;
mBaseUri = baseUri;
}
@@ -1250,7 +1274,7 @@
if (size > 0) {
String [] foo = new String [size];
foo = whereArgs.toArray(foo);
- int numrows = mProvider.delete(mPackageName, mBaseUri,
+ int numrows = mProvider.delete(mBaseUri,
MediaStore.MediaColumns._ID + " IN (" +
whereClause.toString() + ")", foo);
//Log.i("@@@@@@@@@", "rows deleted: " + numrows);
@@ -1271,48 +1295,26 @@
pruneDeadThumbnailFiles();
// allow GC to clean up
- mPlayLists = null;
- mMediaProvider = null;
+ mPlayLists.clear();
}
private void releaseResources() {
// release the DrmManagerClient resources
if (mDrmManagerClient != null) {
- mDrmManagerClient.release();
+ mDrmManagerClient.close();
mDrmManagerClient = null;
}
}
- private void initialize(String volumeName) {
- mMediaProvider = mContext.getContentResolver().acquireProvider("media");
-
- mAudioUri = Audio.Media.getContentUri(volumeName);
- mVideoUri = Video.Media.getContentUri(volumeName);
- mImagesUri = Images.Media.getContentUri(volumeName);
- mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
- mFilesUri = Files.getContentUri(volumeName);
- mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
-
- if (!volumeName.equals("internal")) {
- // we only support playlists on external media
- mProcessPlaylists = true;
- mProcessGenres = true;
- mPlaylistsUri = Playlists.getContentUri(volumeName);
-
- mCaseInsensitivePaths = true;
- }
- }
-
- public void scanDirectories(String[] directories, String volumeName) {
+ public void scanDirectories(String[] directories) {
try {
long start = System.currentTimeMillis();
- initialize(volumeName);
prescan(null, true);
long prescan = System.currentTimeMillis();
if (ENABLE_BULK_INSERTS) {
// create MediaInserter for bulk inserts
- mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
+ mMediaInserter = new MediaInserter(mMediaProvider, 500);
}
for (int i = 0; i < directories.length; i++) {
@@ -1349,9 +1351,8 @@
}
// this function is used to scan a single file
- public Uri scanSingleFile(String path, String volumeName, String mimeType) {
+ public Uri scanSingleFile(String path, String mimeType) {
try {
- initialize(volumeName);
prescan(path, true);
File file = new File(path);
@@ -1464,8 +1465,7 @@
return isNoMediaFile(path);
}
- public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
- initialize(volumeName);
+ public void scanMtpFile(String path, int objectHandle, int format) {
MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
File file = new File(path);
@@ -1481,7 +1481,7 @@
values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
try {
String[] whereArgs = new String[] { Integer.toString(objectHandle) };
- mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
+ mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values,
"_id=?", whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in scanMtpFile", e);
@@ -1498,7 +1498,7 @@
FileEntry entry = makeEntryFor(path);
if (entry != null) {
- fileList = mMediaProvider.query(mPackageName, mFilesUri,
+ fileList = mMediaProvider.query(mFilesUri,
FILES_PRESCAN_PROJECTION, null, null, null, null);
processPlayList(entry, fileList);
}
@@ -1529,7 +1529,7 @@
try {
where = Files.FileColumns.DATA + "=?";
selectionArgs = new String[] { path };
- c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
where, selectionArgs, null, null);
if (c.moveToFirst()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
@@ -1641,7 +1641,7 @@
values.clear();
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
- mMediaProvider.insert(mPackageName, playlistUri, values);
+ mMediaProvider.insert(playlistUri, values);
index++;
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
@@ -1806,16 +1806,16 @@
if (rowId == 0) {
values.put(MediaStore.Audio.Playlists.DATA, path);
- uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
+ uri = mMediaProvider.insert(mPlaylistsUri, values);
rowId = ContentUris.parseId(uri);
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
} else {
uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
- mMediaProvider.update(mPackageName, uri, values, null, null);
+ mMediaProvider.update(uri, values, null, null);
// delete members of existing playlist
membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
- mMediaProvider.delete(mPackageName, membersUri, null, null);
+ mMediaProvider.delete(membersUri, null, null);
}
String playListDirectory = path.substring(0, lastSlash + 1);
@@ -1837,7 +1837,7 @@
try {
// use the files uri and projection because we need the format column,
// but restrict the query to just audio files
- fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
+ fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
"media_type=2", null, null, null);
while (iterator.hasNext()) {
FileEntry entry = iterator.next();
@@ -1856,7 +1856,7 @@
private native void processDirectory(String path, MediaScannerClient client);
private native void processFile(String path, String mimeType, MediaScannerClient client);
- public native void setLocale(String locale);
+ private native void setLocale(String locale);
public native byte[] extractAlbumArt(FileDescriptor fd);
@@ -1864,19 +1864,22 @@
private native final void native_setup();
private native final void native_finalize();
- /**
- * Releases resources associated with this MediaScanner object.
- * It is considered good practice to call this method when
- * one is done using the MediaScanner object. After this method
- * is called, the MediaScanner object can no longer be used.
- */
- public void release() {
- native_finalize();
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ mMediaProvider.close();
+ native_finalize();
+ }
}
@Override
- protected void finalize() {
- mContext.getContentResolver().releaseProvider(mMediaProvider);
- native_finalize();
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
}
}
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index be9fb47..4ca89a8 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -574,6 +574,9 @@
Log.d(TAG, " mMediaSessionToken=" + mMediaSessionToken);
}
+ /**
+ * A class with information on a single media item for use in browsing media.
+ */
public static class MediaItem implements Parcelable {
private final int mFlags;
private final MediaDescription mDescription;
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index e9c94c0..6a13f82 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -129,9 +129,8 @@
* The TV input is connected.
*
* <p>This state indicates that a source device is connected to the input port and is in the
- * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input. This is
- * the default state for any hardware inputs where their states are unknown. Non-hardware inputs
- * are considered connected all the time.
+ * normal operation mode. It is mostly relevant to hardware inputs such as HDMI input.
+ * Non-hardware inputs are considered connected all the time.
*
* @see #getInputState
* @see TvInputManager.TvInputCallback#onInputStateChanged
@@ -141,7 +140,8 @@
* The TV input is connected but in standby mode.
*
* <p>This state indicates that a source device is connected to the input port but is in standby
- * mode. It is mostly relevant to hardware inputs such as HDMI input.
+ * or low power mode. It is mostly relevant to hardware inputs such as HDMI inputs and Component
+ * inputs.
*
* @see #getInputState
* @see TvInputManager.TvInputCallback#onInputStateChanged
diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java
index 0c2f3fe..eae83cf 100644
--- a/media/java/android/media/tv/TvStreamConfig.java
+++ b/media/java/android/media/tv/TvStreamConfig.java
@@ -28,8 +28,15 @@
public class TvStreamConfig implements Parcelable {
static final String TAG = TvStreamConfig.class.getSimpleName();
+ // Must be in sync with tv_input.h
public final static int STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE = 1;
public final static int STREAM_TYPE_BUFFER_PRODUCER = 2;
+ /**
+ * A flag indicating whether the HAL is sure about signal at this stream. Note that
+ * value of 0 here does not necessarily mean no signal. It just means that it may not have
+ * signal and the underlying layer is not sure.
+ */
+ public static final int FLAG_MASK_SIGNAL_DETECTION = 0x1;
private int mStreamId;
private int mType;
@@ -41,6 +48,10 @@
* via tv_input_device::get_stream_configurations().
*/
private int mGeneration;
+ /**
+ * Flags for stream status. See FLAG_MASK_* for details.
+ */
+ private int mFlags;
public static final Parcelable.Creator<TvStreamConfig> CREATOR =
new Parcelable.Creator<TvStreamConfig>() {
@@ -52,7 +63,8 @@
type(source.readInt()).
maxWidth(source.readInt()).
maxHeight(source.readInt()).
- generation(source.readInt()).build();
+ generation(source.readInt()).
+ flags(source.readInt()).build();
} catch (Exception e) {
Log.e(TAG, "Exception creating TvStreamConfig from parcel", e);
return null;
@@ -87,6 +99,10 @@
return mGeneration;
}
+ public int getFlags() {
+ return mFlags;
+ }
+
@Override
public String toString() {
return "TvStreamConfig {mStreamId=" + mStreamId + ";" + "mType=" + mType + ";mGeneration="
@@ -106,6 +122,7 @@
dest.writeInt(mMaxWidth);
dest.writeInt(mMaxHeight);
dest.writeInt(mGeneration);
+ dest.writeInt(mFlags);
}
/**
@@ -117,6 +134,7 @@
private Integer mMaxWidth;
private Integer mMaxHeight;
private Integer mGeneration;
+ private int mFlags = 0;
public Builder() {
}
@@ -146,6 +164,11 @@
return this;
}
+ public Builder flags(int flag) {
+ mFlags = flag;
+ return this;
+ }
+
public TvStreamConfig build() {
if (mStreamId == null || mType == null || mMaxWidth == null || mMaxHeight == null
|| mGeneration == null) {
@@ -158,6 +181,7 @@
config.mMaxWidth = mMaxWidth;
config.mMaxHeight = mMaxHeight;
config.mGeneration = mGeneration;
+ config.mFlags = mFlags;
return config;
}
}
@@ -172,6 +196,7 @@
&& config.mStreamId == mStreamId
&& config.mType == mType
&& config.mMaxWidth == mMaxWidth
- && config.mMaxHeight == mMaxHeight;
+ && config.mMaxHeight == mMaxHeight
+ && config.mFlags == mFlags;
}
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 3541fba..bc96e2e 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -17,9 +17,9 @@
package android.mtp;
import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
-import android.content.IContentProvider;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
@@ -37,23 +37,30 @@
import android.view.Display;
import android.view.WindowManager;
+import dalvik.system.CloseGuard;
+
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* {@hide}
*/
-public class MtpDatabase {
-
+public class MtpDatabase implements AutoCloseable {
private static final String TAG = "MtpDatabase";
private final Context mContext;
private final String mPackageName;
- private final IContentProvider mMediaProvider;
+ private final ContentProviderClient mMediaProvider;
private final String mVolumeName;
private final Uri mObjectsUri;
+ private final MediaScanner mMediaScanner;
+
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
// path to primary storage
private final String mMediaStoragePath;
// if not null, restrict all queries to these subdirectories
@@ -120,7 +127,6 @@
private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
+ Files.FileColumns.PARENT + "=?";
- private final MediaScanner mMediaScanner;
private MtpServer mServer;
// read from native code
@@ -156,11 +162,12 @@
mContext = context;
mPackageName = context.getPackageName();
- mMediaProvider = context.getContentResolver().acquireProvider("media");
+ mMediaProvider = context.getContentResolver()
+ .acquireContentProviderClient(MediaStore.AUTHORITY);
mVolumeName = volumeName;
mMediaStoragePath = storagePath;
mObjectsUri = Files.getMtpObjectsUri(volumeName);
- mMediaScanner = new MediaScanner(context);
+ mMediaScanner = new MediaScanner(context, mVolumeName);
mSubDirectories = subDirectories;
if (subDirectories != null) {
@@ -187,20 +194,9 @@
}
}
- // Set locale to MediaScanner.
- Locale locale = context.getResources().getConfiguration().locale;
- if (locale != null) {
- String language = locale.getLanguage();
- String country = locale.getCountry();
- if (language != null) {
- if (country != null) {
- mMediaScanner.setLocale(language + "_" + country);
- } else {
- mMediaScanner.setLocale(language);
- }
- }
- }
initDeviceProperties(context);
+
+ mCloseGuard.open("close");
}
public void setServer(MtpServer server) {
@@ -221,9 +217,20 @@
}
@Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ mMediaScanner.close();
+ mMediaProvider.close();
+ native_finalize();
+ }
+ }
+
+ @Override
protected void finalize() throws Throwable {
try {
- native_finalize();
+ mCloseGuard.warnIfOpen();
+ close();
} finally {
super.finalize();
}
@@ -334,7 +341,7 @@
if (path != null) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
+ c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
new String[] { path }, null, null);
if (c != null && c.getCount() > 0) {
Log.w(TAG, "file already exists in beginSendObject: " + path);
@@ -359,7 +366,7 @@
values.put(Files.FileColumns.DATE_MODIFIED, modified);
try {
- Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
+ Uri uri = mMediaProvider.insert(mObjectsUri, values);
if (uri != null) {
return Integer.parseInt(uri.getPathSegments().get(2));
} else {
@@ -394,13 +401,13 @@
values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
try {
- Uri uri = mMediaProvider.insert(mPackageName,
+ Uri uri = mMediaProvider.insert(
Audio.Playlists.EXTERNAL_CONTENT_URI, values);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in endSendObject", e);
}
} else {
- mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+ mMediaScanner.scanMtpFile(path, handle, format);
}
} else {
deleteFile(handle);
@@ -503,7 +510,7 @@
}
}
- return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
+ return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where,
whereArgs, null, null);
}
@@ -721,7 +728,7 @@
propertyGroup = mPropertyGroupsByFormat.get(format);
if (propertyGroup == null) {
int[] propertyList = getSupportedObjectProperties(format);
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
mVolumeName, propertyList);
mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
}
@@ -729,7 +736,7 @@
propertyGroup = mPropertyGroupsByProperty.get(property);
if (propertyGroup == null) {
int[] propertyList = new int[] { (int)property };
- propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
mVolumeName, propertyList);
mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
}
@@ -745,7 +752,7 @@
String path = null;
String[] whereArgs = new String[] { Integer.toString(handle) };
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
+ c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE,
whereArgs, null, null);
if (c != null && c.moveToNext()) {
path = c.getString(1);
@@ -788,7 +795,7 @@
try {
// note - we are relying on a special case in MediaProvider.update() to update
// the paths for all children in the case where this is a directory.
- updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
+ updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in mMediaProvider.update", e);
}
@@ -805,7 +812,7 @@
if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
// directory was unhidden
try {
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -815,7 +822,7 @@
if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
&& !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
try {
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + newPath);
}
@@ -886,7 +893,7 @@
char[] outName, long[] outCreatedModified) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
outStorageFormatParent[0] = c.getInt(1);
@@ -933,7 +940,7 @@
}
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
String path = c.getString(1);
@@ -960,7 +967,7 @@
private int getObjectFormat(int handle) {
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
return c.getInt(1);
@@ -984,7 +991,7 @@
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+ c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
if (c != null && c.moveToNext()) {
// don't convert to media path here, since we will be matching
@@ -1007,7 +1014,7 @@
if (format == MtpConstants.FORMAT_ASSOCIATION) {
// recursive case - delete all children first
Uri uri = Files.getMtpObjectsUri(mVolumeName);
- int count = mMediaProvider.delete(mPackageName, uri,
+ int count = mMediaProvider.delete(uri,
// the 'like' makes it use the index, the 'lower()' makes it correct
// when the path contains sqlite wildcard characters
"_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -1015,12 +1022,12 @@
}
Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
- if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
+ if (mMediaProvider.delete(uri, null, null) > 0) {
if (format != MtpConstants.FORMAT_ASSOCIATION
&& path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
try {
String parentPath = path.substring(0, path.lastIndexOf("/"));
- mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
+ mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
} catch (RemoteException e) {
Log.e(TAG, "failed to unhide/rescan for " + path);
}
@@ -1043,7 +1050,7 @@
Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
Cursor c = null;
try {
- c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
+ c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
if (c == null) {
return null;
}
@@ -1077,7 +1084,7 @@
valuesList[i] = values;
}
try {
- if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
+ if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
return MtpConstants.RESPONSE_OK;
}
} catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 95cb520..d24c5e8 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -19,9 +19,10 @@
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.os.CancellationSignal;
-import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
+import java.io.IOException;
+
/**
* This class represents an MTP or PTP device connected on the USB host bus. An application can
* instantiate an object of this type, by referencing an attached {@link
@@ -158,6 +159,22 @@
}
/**
+ * Obtains object bytes in the specified range and writes it to an array.
+ * This call may block for an arbitrary amount of time depending on the size
+ * of the data and speed of the devices.
+ *
+ * @param objectHandle handle of the object to read
+ * @param offset Start index of reading range.
+ * @param size Size of reading range.
+ * @param buffer Array to write data.
+ * @return Size of bytes that are actually read.
+ */
+ public int getPartialObject(int objectHandle, int offset, int size, byte[] buffer)
+ throws IOException {
+ return native_get_partial_object(objectHandle, offset, size, buffer);
+ }
+
+ /**
* Returns the thumbnail data for an object as a byte array.
* The size and format of the thumbnail data can be determined via
* {@link MtpObjectInfo#getThumbCompressedSize} and
@@ -323,6 +340,8 @@
private native int[] native_get_object_handles(int storageId, int format, int objectHandle);
private native MtpObjectInfo native_get_object_info(int objectHandle);
private native byte[] native_get_object(int objectHandle, int objectSize);
+ private native int native_get_partial_object(
+ int objectHandle, int offset, int objectSize, byte[] buffer) throws IOException;
private native byte[] native_get_thumbnail(int objectHandle);
private native boolean native_delete_object(int objectHandle);
private native long native_get_parent(int objectHandle);
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index c80adfa..dea3008 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -16,7 +16,7 @@
package android.mtp;
-import android.content.IContentProvider;
+import android.content.ContentProviderClient;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
@@ -48,8 +48,7 @@
}
private final MtpDatabase mDatabase;
- private final IContentProvider mProvider;
- private final String mPackageName;
+ private final ContentProviderClient mProvider;
private final String mVolumeName;
private final Uri mUri;
@@ -65,13 +64,12 @@
private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE;
// constructs a property group for a list of properties
- public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName,
- String volume, int[] properties) {
+ public MtpPropertyGroup(MtpDatabase database, ContentProviderClient provider, String volumeName,
+ int[] properties) {
mDatabase = database;
mProvider = provider;
- mPackageName = packageName;
- mVolumeName = volume;
- mUri = Files.getMtpObjectsUri(volume);
+ mVolumeName = volumeName;
+ mUri = Files.getMtpObjectsUri(volumeName);
int count = properties.length;
ArrayList<String> columns = new ArrayList<String>(count);
@@ -201,7 +199,7 @@
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mPackageName, mUri,
+ c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -221,7 +219,7 @@
private String queryAudio(int id, String column) {
Cursor c = null;
try {
- c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName),
+ c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -242,7 +240,7 @@
Cursor c = null;
try {
Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
- c = mProvider.query(mPackageName, uri,
+ c = mProvider.query(uri,
new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
null, null, null, null);
if (c != null && c.moveToNext()) {
@@ -264,7 +262,7 @@
Cursor c = null;
try {
// for now we are only reading properties from the "objects" table
- c = mProvider.query(mPackageName, mUri,
+ c = mProvider.query(mUri,
new String [] { Files.FileColumns._ID, column },
ID_WHERE, new String[] { Integer.toString(id) }, null, null);
if (c != null && c.moveToNext()) {
@@ -335,7 +333,7 @@
try {
// don't query if not necessary
if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
- c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null);
+ c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
if (c == null) {
return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index f2c6a6c..8edccac 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -546,7 +546,7 @@
}
/**
- * Gets any extras about the brwoser service.
+ * Gets any extras about the browser service.
*/
public Bundle getExtras() {
return mExtras;
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 3f4d183..14c15e5 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -29,6 +29,7 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
+#include "nativehelper/ScopedLocalRef.h"
#include "private/android_filesystem_config.h"
#include "MtpTypes.h"
@@ -41,6 +42,8 @@
// ----------------------------------------------------------------------------
+namespace {
+
static jfieldID field_context;
jclass clazz_deviceInfo;
@@ -93,6 +96,29 @@
// MtpEvent fields
static jfieldID field_event_eventCode;
+class JavaArrayWriter {
+public:
+ JavaArrayWriter(JNIEnv* env, jbyteArray array) :
+ mEnv(env), mArray(array), mSize(mEnv->GetArrayLength(mArray)) {}
+ bool write(void* data, uint32_t offset, uint32_t length) {
+ if (static_cast<uint32_t>(mSize) < offset + length) {
+ return false;
+ }
+ mEnv->SetByteArrayRegion(mArray, offset, length, static_cast<jbyte*>(data));
+ return true;
+ }
+ static bool writeTo(void* data, uint32_t offset, uint32_t length, void* clientData) {
+ return static_cast<JavaArrayWriter*>(clientData)->write(data, offset, length);
+ }
+
+private:
+ JNIEnv* mEnv;
+ jbyteArray mArray;
+ jsize mSize;
+};
+
+}
+
MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
{
return (MtpDevice*)env->GetLongField(javaDevice, field_context);
@@ -307,38 +333,59 @@
return info;
}
-struct get_object_callback_data {
- JNIEnv *env;
- jbyteArray array;
-};
-
-static bool get_object_callback(void* data, int offset, int length, void* clientData)
-{
- get_object_callback_data* cbData = (get_object_callback_data *)clientData;
- cbData->env->SetByteArrayRegion(cbData->array, offset, length, (jbyte *)data);
- return true;
-}
-
static jbyteArray
android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize)
{
MtpDevice* device = get_device_from_object(env, thiz);
- if (!device)
- return NULL;
-
- jbyteArray array = env->NewByteArray(objectSize);
- if (!array) {
- jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
- return NULL;
+ if (!device) {
+ return nullptr;
}
- get_object_callback_data data;
- data.env = env;
- data.array = array;
+ ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(objectSize));
+ if (!array.get()) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
+ return nullptr;
+ }
- if (device->readObject(objectID, get_object_callback, objectSize, &data))
- return array;
- return NULL;
+ JavaArrayWriter writer(env, array.get());
+
+ if (device->readObject(objectID, JavaArrayWriter::writeTo, objectSize, &writer)) {
+ return array.release();
+ }
+ return nullptr;
+}
+
+static jint
+android_mtp_MtpDevice_get_partial_object(JNIEnv *env,
+ jobject thiz,
+ jint objectID,
+ jint offset,
+ jint size,
+ jbyteArray array)
+{
+ if (!array) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null.");
+ return -1;
+ }
+
+ MtpDevice* const device = get_device_from_object(env, thiz);
+ if (!device) {
+ jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice.");
+ return -1;
+ }
+
+ JavaArrayWriter writer(env, array);
+ uint32_t written_size;
+ bool success = device->readPartialObject(
+ objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer);
+ if (!success) {
+ jniThrowException(env, "java/io/IOException", "Failed to read data.");
+ return -1;
+ }
+ // Note: assumption here is that a negative value will be treated as unsigned on the Java
+ // level.
+ // TODO: Make sure that actually holds.
+ return static_cast<jint>(written_size);
}
static jbyteArray
@@ -547,6 +594,7 @@
{"native_get_object_info", "(I)Landroid/mtp/MtpObjectInfo;",
(void *)android_mtp_MtpDevice_get_object_info},
{"native_get_object", "(II)[B",(void *)android_mtp_MtpDevice_get_object},
+ {"native_get_partial_object", "(III[B)I", (void *)android_mtp_MtpDevice_get_partial_object},
{"native_get_thumbnail", "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail},
{"native_delete_object", "(I)Z", (void *)android_mtp_MtpDevice_delete_object},
{"native_get_parent", "(I)J", (void *)android_mtp_MtpDevice_get_parent},
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 70d651f..b63df6f 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -655,7 +655,7 @@
goto error;
}
- if ((numChannels < 1) || (numChannels > 8)) {
+ if ((numChannels < 1) || (numChannels > FCC_8)) {
ALOGE("Sample channel count (%d) out of range", numChannels);
status = BAD_VALUE;
goto error;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 05df014..06efa90 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,6 +16,7 @@
package com.android.mediaframeworktest.unit;
+import android.content.ContentProviderClient;
import android.content.ContentValues;
import android.content.IContentProvider;
import android.media.MediaInserter;
@@ -81,8 +82,9 @@
protected void setUp() throws Exception {
super.setUp();
mMockProvider = EasyMock.createMock(IContentProvider.class);
- mMediaInserter = new MediaInserter(mMockProvider,
- mPackageName, TEST_BUFFER_SIZE);
+ final ContentProviderClient client = new ContentProviderClient(
+ getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+ mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
mPackageName = getInstrumentation().getContext().getPackageName();
mFilesCounter = 0;
mAudioCounter = 0;
diff --git a/opengl/java/android/opengl/GLES31.java b/opengl/java/android/opengl/GLES31.java
index 805930e..679108f 100644
--- a/opengl/java/android/opengl/GLES31.java
+++ b/opengl/java/android/opengl/GLES31.java
@@ -204,7 +204,8 @@
_nativeClassInit();
}
- private GLES31() {}
+ /** @hide */
+ GLES31() {}
// C function void glDispatchCompute ( GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z )
public static native void glDispatchCompute(
diff --git a/opengl/java/android/opengl/GLES32.java b/opengl/java/android/opengl/GLES32.java
new file mode 100644
index 0000000..7a392b8
--- /dev/null
+++ b/opengl/java/android/opengl/GLES32.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This source file is automatically generated
+
+package android.opengl;
+
+/** OpenGL ES 3.2
+ */
+public class GLES32 extends GLES31 {
+
+ public static final int GL_CONTEXT_FLAG_DEBUG_BIT = 0x00000002;
+
+ public static final int GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT = 0x00000004;
+
+ public static final int GL_GEOMETRY_SHADER_BIT = 0x00000004;
+ public static final int GL_TESS_CONTROL_SHADER_BIT = 0x00000008;
+ public static final int GL_TESS_EVALUATION_SHADER_BIT = 0x00000010;
+
+ public static final int GL_QUADS = 0x0007;
+ public static final int GL_LINES_ADJACENCY = 0x000A;
+ public static final int GL_LINE_STRIP_ADJACENCY = 0x000B;
+ public static final int GL_TRIANGLES_ADJACENCY = 0x000C;
+ public static final int GL_TRIANGLE_STRIP_ADJACENCY = 0x000D;
+ public static final int GL_PATCHES = 0x000E;
+ public static final int GL_STACK_OVERFLOW = 0x0503;
+ public static final int GL_STACK_UNDERFLOW = 0x0504;
+ public static final int GL_CONTEXT_LOST = 0x0507;
+ public static final int GL_TEXTURE_BORDER_COLOR = 0x1004;
+ public static final int GL_VERTEX_ARRAY = 0x8074;
+ public static final int GL_CLAMP_TO_BORDER = 0x812D;
+ public static final int GL_CONTEXT_FLAGS = 0x821E;
+ public static final int GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED = 0x8221;
+ public static final int GL_DEBUG_OUTPUT_SYNCHRONOUS = 0x8242;
+ public static final int GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH = 0x8243;
+ public static final int GL_DEBUG_CALLBACK_FUNCTION = 0x8244;
+ public static final int GL_DEBUG_CALLBACK_USER_PARAM = 0x8245;
+ public static final int GL_DEBUG_SOURCE_API = 0x8246;
+ public static final int GL_DEBUG_SOURCE_WINDOW_SYSTEM = 0x8247;
+ public static final int GL_DEBUG_SOURCE_SHADER_COMPILER = 0x8248;
+ public static final int GL_DEBUG_SOURCE_THIRD_PARTY = 0x8249;
+ public static final int GL_DEBUG_SOURCE_APPLICATION = 0x824A;
+ public static final int GL_DEBUG_SOURCE_OTHER = 0x824B;
+ public static final int GL_DEBUG_TYPE_ERROR = 0x824C;
+ public static final int GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR = 0x824D;
+ public static final int GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR = 0x824E;
+ public static final int GL_DEBUG_TYPE_PORTABILITY = 0x824F;
+ public static final int GL_DEBUG_TYPE_PERFORMANCE = 0x8250;
+ public static final int GL_DEBUG_TYPE_OTHER = 0x8251;
+ public static final int GL_LOSE_CONTEXT_ON_RESET = 0x8252;
+ public static final int GL_GUILTY_CONTEXT_RESET = 0x8253;
+ public static final int GL_INNOCENT_CONTEXT_RESET = 0x8254;
+ public static final int GL_UNKNOWN_CONTEXT_RESET = 0x8255;
+ public static final int GL_RESET_NOTIFICATION_STRATEGY = 0x8256;
+ public static final int GL_LAYER_PROVOKING_VERTEX = 0x825E;
+ public static final int GL_UNDEFINED_VERTEX = 0x8260;
+ public static final int GL_NO_RESET_NOTIFICATION = 0x8261;
+ public static final int GL_DEBUG_TYPE_MARKER = 0x8268;
+ public static final int GL_DEBUG_TYPE_PUSH_GROUP = 0x8269;
+ public static final int GL_DEBUG_TYPE_POP_GROUP = 0x826A;
+ public static final int GL_DEBUG_SEVERITY_NOTIFICATION = 0x826B;
+ public static final int GL_MAX_DEBUG_GROUP_STACK_DEPTH = 0x826C;
+ public static final int GL_DEBUG_GROUP_STACK_DEPTH = 0x826D;
+ public static final int GL_BUFFER = 0x82E0;
+ public static final int GL_SHADER = 0x82E1;
+ public static final int GL_PROGRAM = 0x82E2;
+ public static final int GL_QUERY = 0x82E3;
+ public static final int GL_PROGRAM_PIPELINE = 0x82E4;
+ public static final int GL_SAMPLER = 0x82E6;
+ public static final int GL_MAX_LABEL_LENGTH = 0x82E8;
+ public static final int GL_MAX_TESS_CONTROL_INPUT_COMPONENTS = 0x886C;
+ public static final int GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS = 0x886D;
+ public static final int GL_GEOMETRY_SHADER_INVOCATIONS = 0x887F;
+ public static final int GL_GEOMETRY_VERTICES_OUT = 0x8916;
+ public static final int GL_GEOMETRY_INPUT_TYPE = 0x8917;
+ public static final int GL_GEOMETRY_OUTPUT_TYPE = 0x8918;
+ public static final int GL_MAX_GEOMETRY_UNIFORM_BLOCKS = 0x8A2C;
+ public static final int GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS = 0x8A32;
+ public static final int GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS = 0x8C29;
+ public static final int GL_TEXTURE_BUFFER = 0x8C2A;
+ public static final int GL_TEXTURE_BUFFER_BINDING = 0x8C2A;
+ public static final int GL_MAX_TEXTURE_BUFFER_SIZE = 0x8C2B;
+ public static final int GL_TEXTURE_BINDING_BUFFER = 0x8C2C;
+ public static final int GL_TEXTURE_BUFFER_DATA_STORE_BINDING = 0x8C2D;
+ public static final int GL_SAMPLE_SHADING = 0x8C36;
+ public static final int GL_MIN_SAMPLE_SHADING_VALUE = 0x8C37;
+ public static final int GL_PRIMITIVES_GENERATED = 0x8C87;
+ public static final int GL_FRAMEBUFFER_ATTACHMENT_LAYERED = 0x8DA7;
+ public static final int GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS = 0x8DA8;
+ public static final int GL_SAMPLER_BUFFER = 0x8DC2;
+ public static final int GL_INT_SAMPLER_BUFFER = 0x8DD0;
+ public static final int GL_UNSIGNED_INT_SAMPLER_BUFFER = 0x8DD8;
+ public static final int GL_GEOMETRY_SHADER = 0x8DD9;
+ public static final int GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 0x8DDF;
+ public static final int GL_MAX_GEOMETRY_OUTPUT_VERTICES = 0x8DE0;
+ public static final int GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 0x8DE1;
+ public static final int GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E1E;
+ public static final int GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E1F;
+ public static final int GL_FIRST_VERTEX_CONVENTION = 0x8E4D;
+ public static final int GL_LAST_VERTEX_CONVENTION = 0x8E4E;
+ public static final int GL_MAX_GEOMETRY_SHADER_INVOCATIONS = 0x8E5A;
+ public static final int GL_MIN_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5B;
+ public static final int GL_MAX_FRAGMENT_INTERPOLATION_OFFSET = 0x8E5C;
+ public static final int GL_FRAGMENT_INTERPOLATION_OFFSET_BITS = 0x8E5D;
+ public static final int GL_PATCH_VERTICES = 0x8E72;
+ public static final int GL_TESS_CONTROL_OUTPUT_VERTICES = 0x8E75;
+ public static final int GL_TESS_GEN_MODE = 0x8E76;
+ public static final int GL_TESS_GEN_SPACING = 0x8E77;
+ public static final int GL_TESS_GEN_VERTEX_ORDER = 0x8E78;
+ public static final int GL_TESS_GEN_POINT_MODE = 0x8E79;
+ public static final int GL_ISOLINES = 0x8E7A;
+ public static final int GL_FRACTIONAL_ODD = 0x8E7B;
+ public static final int GL_FRACTIONAL_EVEN = 0x8E7C;
+ public static final int GL_MAX_PATCH_VERTICES = 0x8E7D;
+ public static final int GL_MAX_TESS_GEN_LEVEL = 0x8E7E;
+ public static final int GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS = 0x8E7F;
+ public static final int GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS = 0x8E80;
+ public static final int GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS = 0x8E81;
+ public static final int GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS = 0x8E82;
+ public static final int GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS = 0x8E83;
+ public static final int GL_MAX_TESS_PATCH_COMPONENTS = 0x8E84;
+ public static final int GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS = 0x8E85;
+ public static final int GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS = 0x8E86;
+ public static final int GL_TESS_EVALUATION_SHADER = 0x8E87;
+ public static final int GL_TESS_CONTROL_SHADER = 0x8E88;
+ public static final int GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS = 0x8E89;
+ public static final int GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS = 0x8E8A;
+ public static final int GL_TEXTURE_CUBE_MAP_ARRAY = 0x9009;
+ public static final int GL_TEXTURE_BINDING_CUBE_MAP_ARRAY = 0x900A;
+ public static final int GL_SAMPLER_CUBE_MAP_ARRAY = 0x900C;
+ public static final int GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW = 0x900D;
+ public static final int GL_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900E;
+ public static final int GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY = 0x900F;
+ public static final int GL_IMAGE_BUFFER = 0x9051;
+ public static final int GL_IMAGE_CUBE_MAP_ARRAY = 0x9054;
+ public static final int GL_INT_IMAGE_BUFFER = 0x905C;
+ public static final int GL_INT_IMAGE_CUBE_MAP_ARRAY = 0x905F;
+ public static final int GL_UNSIGNED_INT_IMAGE_BUFFER = 0x9067;
+ public static final int GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY = 0x906A;
+ public static final int GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS = 0x90CB;
+ public static final int GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS = 0x90CC;
+ public static final int GL_MAX_GEOMETRY_IMAGE_UNIFORMS = 0x90CD;
+ public static final int GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS = 0x90D7;
+ public static final int GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS = 0x90D8;
+ public static final int GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS = 0x90D9;
+ public static final int GL_TEXTURE_2D_MULTISAMPLE_ARRAY = 0x9102;
+ public static final int GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY = 0x9105;
+ public static final int GL_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910B;
+ public static final int GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910C;
+ public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY = 0x910D;
+ public static final int GL_MAX_GEOMETRY_INPUT_COMPONENTS = 0x9123;
+ public static final int GL_MAX_GEOMETRY_OUTPUT_COMPONENTS = 0x9124;
+ public static final int GL_MAX_DEBUG_MESSAGE_LENGTH = 0x9143;
+ public static final int GL_MAX_DEBUG_LOGGED_MESSAGES = 0x9144;
+ public static final int GL_DEBUG_LOGGED_MESSAGES = 0x9145;
+ public static final int GL_DEBUG_SEVERITY_HIGH = 0x9146;
+ public static final int GL_DEBUG_SEVERITY_MEDIUM = 0x9147;
+ public static final int GL_DEBUG_SEVERITY_LOW = 0x9148;
+ public static final int GL_TEXTURE_BUFFER_OFFSET = 0x919D;
+ public static final int GL_TEXTURE_BUFFER_SIZE = 0x919E;
+ public static final int GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT = 0x919F;
+ public static final int GL_MULTIPLY = 0x9294;
+ public static final int GL_SCREEN = 0x9295;
+ public static final int GL_OVERLAY = 0x9296;
+ public static final int GL_DARKEN = 0x9297;
+ public static final int GL_LIGHTEN = 0x9298;
+ public static final int GL_COLORDODGE = 0x9299;
+ public static final int GL_COLORBURN = 0x929A;
+ public static final int GL_HARDLIGHT = 0x929B;
+ public static final int GL_SOFTLIGHT = 0x929C;
+ public static final int GL_DIFFERENCE = 0x929E;
+ public static final int GL_EXCLUSION = 0x92A0;
+ public static final int GL_HSL_HUE = 0x92AD;
+ public static final int GL_HSL_SATURATION = 0x92AE;
+ public static final int GL_HSL_COLOR = 0x92AF;
+ public static final int GL_HSL_LUMINOSITY = 0x92B0;
+ public static final int GL_PRIMITIVE_BOUNDING_BOX = 0x92BE;
+ public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS = 0x92CD;
+ public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS = 0x92CE;
+ public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS = 0x92CF;
+ public static final int GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS = 0x92D3;
+ public static final int GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS = 0x92D4;
+ public static final int GL_MAX_GEOMETRY_ATOMIC_COUNTERS = 0x92D5;
+ public static final int GL_DEBUG_OUTPUT = 0x92E0;
+ public static final int GL_IS_PER_PATCH = 0x92E7;
+ public static final int GL_REFERENCED_BY_TESS_CONTROL_SHADER = 0x9307;
+ public static final int GL_REFERENCED_BY_TESS_EVALUATION_SHADER = 0x9308;
+ public static final int GL_REFERENCED_BY_GEOMETRY_SHADER = 0x9309;
+ public static final int GL_FRAMEBUFFER_DEFAULT_LAYERS = 0x9312;
+ public static final int GL_MAX_FRAMEBUFFER_LAYERS = 0x9317;
+ public static final int GL_MULTISAMPLE_LINE_WIDTH_RANGE = 0x9381;
+ public static final int GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY = 0x9382;
+ public static final int GL_COMPRESSED_RGBA_ASTC_4x4 = 0x93B0;
+ public static final int GL_COMPRESSED_RGBA_ASTC_5x4 = 0x93B1;
+ public static final int GL_COMPRESSED_RGBA_ASTC_5x5 = 0x93B2;
+ public static final int GL_COMPRESSED_RGBA_ASTC_6x5 = 0x93B3;
+ public static final int GL_COMPRESSED_RGBA_ASTC_6x6 = 0x93B4;
+ public static final int GL_COMPRESSED_RGBA_ASTC_8x5 = 0x93B5;
+ public static final int GL_COMPRESSED_RGBA_ASTC_8x6 = 0x93B6;
+ public static final int GL_COMPRESSED_RGBA_ASTC_8x8 = 0x93B7;
+ public static final int GL_COMPRESSED_RGBA_ASTC_10x5 = 0x93B8;
+ public static final int GL_COMPRESSED_RGBA_ASTC_10x6 = 0x93B9;
+ public static final int GL_COMPRESSED_RGBA_ASTC_10x8 = 0x93BA;
+ public static final int GL_COMPRESSED_RGBA_ASTC_10x10 = 0x93BB;
+ public static final int GL_COMPRESSED_RGBA_ASTC_12x10 = 0x93BC;
+ public static final int GL_COMPRESSED_RGBA_ASTC_12x12 = 0x93BD;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 = 0x93D0;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 = 0x93D1;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 = 0x93D2;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 = 0x93D3;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 = 0x93D4;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 = 0x93D5;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 = 0x93D6;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 = 0x93D7;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 = 0x93D8;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 = 0x93D9;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 = 0x93DA;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 = 0x93DB;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 = 0x93DC;
+ public static final int GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 = 0x93DD;
+
+
+ native private static void _nativeClassInit();
+ static {
+ _nativeClassInit();
+ }
+
+ private GLES32() {}
+ // C function void glBlendBarrier ( void )
+
+ public static native void glBlendBarrier(
+ );
+
+ // C function void glCopyImageSubData ( GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth )
+
+ public static native void glCopyImageSubData(
+ int srcName,
+ int srcTarget,
+ int srcLevel,
+ int srcX,
+ int srcY,
+ int srcZ,
+ int dstName,
+ int dstTarget,
+ int dstLevel,
+ int dstX,
+ int dstY,
+ int dstZ,
+ int srcWidth,
+ int srcHeight,
+ int srcDepth
+ );
+
+ // C function void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled )
+
+ public static native void glDebugMessageControl(
+ int source,
+ int type,
+ int severity,
+ int count,
+ int[] ids,
+ int offset,
+ boolean enabled
+ );
+
+ // C function void glDebugMessageControl ( GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled )
+
+ public static native void glDebugMessageControl(
+ int source,
+ int type,
+ int severity,
+ int count,
+ java.nio.IntBuffer ids,
+ boolean enabled
+ );
+
+ // C function void glDebugMessageInsert ( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf )
+
+ public static native void glDebugMessageInsert(
+ int source,
+ int type,
+ int id,
+ int severity,
+ int length,
+ String buf
+ );
+
+ // C function void glDebugMessageCallback ( GLDEBUGPROC callback, const void *userParam )
+
+ public interface DebugProc {
+ void onMessage(int source, int type, int id, int severity, String message);
+ }
+
+ public static native void glDebugMessageCallback(DebugProc callback);
+
+ // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+ public static native int glGetDebugMessageLog(
+ int count,
+ int bufSize,
+ int[] sources,
+ int sourcesOffset,
+ int[] types,
+ int typesOffset,
+ int[] ids,
+ int idsOffset,
+ int[] severities,
+ int severitiesOffset,
+ int[] lengths,
+ int lengthsOffset,
+ byte[] messageLog,
+ int messageLogOffset);
+
+ // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+ public static native int glGetDebugMessageLog(
+ int count,
+ java.nio.IntBuffer sources,
+ java.nio.IntBuffer types,
+ java.nio.IntBuffer ids,
+ java.nio.IntBuffer severities,
+ java.nio.IntBuffer lengths,
+ java.nio.ByteBuffer messageLog);
+
+ // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+ public static native String[] glGetDebugMessageLog(
+ int count,
+ int[] sources,
+ int sourcesOffset,
+ int[] types,
+ int typesOffset,
+ int[] ids,
+ int idsOffset,
+ int[] severities,
+ int severitiesOffset);
+
+ // C function GLuint glGetDebugMessageLog ( GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog )
+
+ public static native String[] glGetDebugMessageLog(
+ int count,
+ java.nio.IntBuffer sources,
+ java.nio.IntBuffer types,
+ java.nio.IntBuffer ids,
+ java.nio.IntBuffer severities);
+
+ // C function void glPushDebugGroup ( GLenum source, GLuint id, GLsizei length, const GLchar *message )
+
+ public static native void glPushDebugGroup(
+ int source,
+ int id,
+ int length,
+ String message
+ );
+
+ // C function void glPopDebugGroup ( void )
+
+ public static native void glPopDebugGroup(
+ );
+
+ // C function void glObjectLabel ( GLenum identifier, GLuint name, GLsizei length, const GLchar *label )
+
+ public static native void glObjectLabel(
+ int identifier,
+ int name,
+ int length,
+ String label
+ );
+
+ // C function void glGetObjectLabel ( GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label )
+
+ public static native String glGetObjectLabel(int identifier, int name);
+
+ // C function void glObjectPtrLabel ( const void *ptr, GLsizei length, const GLchar *label )
+
+ public static native void glObjectPtrLabel(long ptr, String label);
+
+ // C function void glGetObjectPtrLabel ( const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label )
+
+ public static native String glGetObjectPtrLabel(long ptr);
+
+ // C function void glGetPointerv ( GLenum pname, void **params )
+
+ public static native long glGetPointerv(
+ int pname
+ );
+
+ // C function void glEnablei ( GLenum target, GLuint index )
+
+ public static native void glEnablei(
+ int target,
+ int index
+ );
+
+ // C function void glDisablei ( GLenum target, GLuint index )
+
+ public static native void glDisablei(
+ int target,
+ int index
+ );
+
+ // C function void glBlendEquationi ( GLuint buf, GLenum mode )
+
+ public static native void glBlendEquationi(
+ int buf,
+ int mode
+ );
+
+ // C function void glBlendEquationSeparatei ( GLuint buf, GLenum modeRGB, GLenum modeAlpha )
+
+ public static native void glBlendEquationSeparatei(
+ int buf,
+ int modeRGB,
+ int modeAlpha
+ );
+
+ // C function void glBlendFunci ( GLuint buf, GLenum src, GLenum dst )
+
+ public static native void glBlendFunci(
+ int buf,
+ int src,
+ int dst
+ );
+
+ // C function void glBlendFuncSeparatei ( GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )
+
+ public static native void glBlendFuncSeparatei(
+ int buf,
+ int srcRGB,
+ int dstRGB,
+ int srcAlpha,
+ int dstAlpha
+ );
+
+ // C function void glColorMaski ( GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a )
+
+ public static native void glColorMaski(
+ int index,
+ boolean r,
+ boolean g,
+ boolean b,
+ boolean a
+ );
+
+ // C function GLboolean glIsEnabledi ( GLenum target, GLuint index )
+
+ public static native boolean glIsEnabledi(
+ int target,
+ int index
+ );
+
+ // C function void glDrawElementsBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex )
+
+ public static native void glDrawElementsBaseVertex(
+ int mode,
+ int count,
+ int type,
+ java.nio.Buffer indices,
+ int basevertex
+ );
+
+ // C function void glDrawRangeElementsBaseVertex ( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex )
+
+ public static native void glDrawRangeElementsBaseVertex(
+ int mode,
+ int start,
+ int end,
+ int count,
+ int type,
+ java.nio.Buffer indices,
+ int basevertex
+ );
+
+ // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex )
+
+ public static native void glDrawElementsInstancedBaseVertex(
+ int mode,
+ int count,
+ int type,
+ java.nio.Buffer indices,
+ int instanceCount,
+ int basevertex
+ );
+
+ // C function void glDrawElementsInstancedBaseVertex ( GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount, GLint basevertex )
+
+ public static native void glDrawElementsInstancedBaseVertex(
+ int mode,
+ int count,
+ int type,
+ int indicesOffset,
+ int instanceCount,
+ int basevertex
+ );
+
+ // C function void glFramebufferTexture ( GLenum target, GLenum attachment, GLuint texture, GLint level )
+
+ public static native void glFramebufferTexture(
+ int target,
+ int attachment,
+ int texture,
+ int level
+ );
+
+ // C function void glPrimitiveBoundingBox ( GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW )
+
+ public static native void glPrimitiveBoundingBox(
+ float minX,
+ float minY,
+ float minZ,
+ float minW,
+ float maxX,
+ float maxY,
+ float maxZ,
+ float maxW
+ );
+
+ // C function GLenum glGetGraphicsResetStatus ( void )
+
+ public static native int glGetGraphicsResetStatus(
+ );
+
+ // C function void glReadnPixels ( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data )
+
+ public static native void glReadnPixels(
+ int x,
+ int y,
+ int width,
+ int height,
+ int format,
+ int type,
+ int bufSize,
+ java.nio.Buffer data
+ );
+
+ // C function void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
+
+ public static native void glGetnUniformfv(
+ int program,
+ int location,
+ int bufSize,
+ float[] params,
+ int offset
+ );
+
+ // C function void glGetnUniformfv ( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
+
+ public static native void glGetnUniformfv(
+ int program,
+ int location,
+ int bufSize,
+ java.nio.FloatBuffer params
+ );
+
+ // C function void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params )
+
+ public static native void glGetnUniformiv(
+ int program,
+ int location,
+ int bufSize,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetnUniformiv ( GLuint program, GLint location, GLsizei bufSize, GLint *params )
+
+ public static native void glGetnUniformiv(
+ int program,
+ int location,
+ int bufSize,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
+
+ public static native void glGetnUniformuiv(
+ int program,
+ int location,
+ int bufSize,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetnUniformuiv ( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
+
+ public static native void glGetnUniformuiv(
+ int program,
+ int location,
+ int bufSize,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glMinSampleShading ( GLfloat value )
+
+ public static native void glMinSampleShading(
+ float value
+ );
+
+ // C function void glPatchParameteri ( GLenum pname, GLint value )
+
+ public static native void glPatchParameteri(
+ int pname,
+ int value
+ );
+
+ // C function void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params )
+
+ public static native void glTexParameterIiv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glTexParameterIiv ( GLenum target, GLenum pname, const GLint *params )
+
+ public static native void glTexParameterIiv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params )
+
+ public static native void glTexParameterIuiv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glTexParameterIuiv ( GLenum target, GLenum pname, const GLuint *params )
+
+ public static native void glTexParameterIuiv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params )
+
+ public static native void glGetTexParameterIiv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetTexParameterIiv ( GLenum target, GLenum pname, GLint *params )
+
+ public static native void glGetTexParameterIiv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params )
+
+ public static native void glGetTexParameterIuiv(
+ int target,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetTexParameterIuiv ( GLenum target, GLenum pname, GLuint *params )
+
+ public static native void glGetTexParameterIuiv(
+ int target,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param )
+
+ public static native void glSamplerParameterIiv(
+ int sampler,
+ int pname,
+ int[] param,
+ int offset
+ );
+
+ // C function void glSamplerParameterIiv ( GLuint sampler, GLenum pname, const GLint *param )
+
+ public static native void glSamplerParameterIiv(
+ int sampler,
+ int pname,
+ java.nio.IntBuffer param
+ );
+
+ // C function void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param )
+
+ public static native void glSamplerParameterIuiv(
+ int sampler,
+ int pname,
+ int[] param,
+ int offset
+ );
+
+ // C function void glSamplerParameterIuiv ( GLuint sampler, GLenum pname, const GLuint *param )
+
+ public static native void glSamplerParameterIuiv(
+ int sampler,
+ int pname,
+ java.nio.IntBuffer param
+ );
+
+ // C function void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params )
+
+ public static native void glGetSamplerParameterIiv(
+ int sampler,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetSamplerParameterIiv ( GLuint sampler, GLenum pname, GLint *params )
+
+ public static native void glGetSamplerParameterIiv(
+ int sampler,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params )
+
+ public static native void glGetSamplerParameterIuiv(
+ int sampler,
+ int pname,
+ int[] params,
+ int offset
+ );
+
+ // C function void glGetSamplerParameterIuiv ( GLuint sampler, GLenum pname, GLuint *params )
+
+ public static native void glGetSamplerParameterIuiv(
+ int sampler,
+ int pname,
+ java.nio.IntBuffer params
+ );
+
+ // C function void glTexBuffer ( GLenum target, GLenum internalformat, GLuint buffer )
+
+ public static native void glTexBuffer(
+ int target,
+ int internalformat,
+ int buffer
+ );
+
+ // C function void glTexBufferRange ( GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size )
+
+ public static native void glTexBufferRange(
+ int target,
+ int internalformat,
+ int buffer,
+ int offset,
+ int size
+ );
+
+ // C function void glTexStorage3DMultisample ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations )
+
+ public static native void glTexStorage3DMultisample(
+ int target,
+ int samples,
+ int internalformat,
+ int width,
+ int height,
+ int depth,
+ boolean fixedsamplelocations
+ );
+
+}
diff --git a/packages/BackupRestoreConfirmation/res/values-b+sr+Latn/strings.xml b/packages/BackupRestoreConfirmation/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..c46ff49
--- /dev/null
+++ b/packages/BackupRestoreConfirmation/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,39 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="backup_confirm_title" msgid="827563724209303345">"Rezervna kopije svih podataka"</string>
+ <string name="restore_confirm_title" msgid="5469365809567486602">"Potpuno vraćanje"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Zahtevana je potpuna rezervna kopija svih podataka na povezani stoni računar. Da li želite da dozvolite to?\n\nAko niste lično zahtevali rezervnu kopiju, ne dozvoljavajte nastavak radnje."</string>
+ <string name="allow_backup_button_label" msgid="4217228747769644068">"Napravi rezervnu kopiju mojih podataka"</string>
+ <string name="deny_backup_button_label" msgid="6009119115581097708">"Ne pravi rezervne kopije"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"Zahtevano je potpuno vraćanje svih podataka sa povezanog stonog računara. Da li želite da dozvolite to?\n\nAko niste lično zahtevali vraćanje, ne dozvoljavajte nastavak radnje. Time ćete zameniti sve podatke koji su trenutno na uređaju!"</string>
+ <string name="allow_restore_button_label" msgid="3081286752277127827">"Vrati moje podatke"</string>
+ <string name="deny_restore_button_label" msgid="1724367334453104378">"Ne vraćaj"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Unesite trenutnu lozinku rezervne kopije u nastavku:"</string>
+ <string name="device_encryption_restore_text" msgid="1570864916855208992">"Unesite lozinku uređaja za šifrovanje u nastavku."</string>
+ <string name="device_encryption_backup_text" msgid="5866590762672844664">"Unesite lozinku uređaja za šifrovanje. Ovo će se koristiti i za šifrovanje rezervne arhive."</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Unesite lozinku koju ćete koristiti za šifrovanje podataka potpune rezervne kopije. Ako to polje ostavite prazno, koristiće se trenutna lozinka rezervne kopije:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ako želite da šifrujete podatke potpune rezervne kopije, unesite lozinku u nastavku."</string>
+ <string name="backup_enc_password_required" msgid="7889652203371654149">"Pošto vam je uređaj šifrovan, morate da šifrujete rezervnu kopiju. Unesite lozinku u nastavku:"</string>
+ <string name="restore_enc_password_text" msgid="6140898525580710823">"Ako su podaci za vraćanje šifrovani, unesite lozinku u nastavku:"</string>
+ <string name="toast_backup_started" msgid="550354281452756121">"Pokretanje pravljenja rezervne kopije..."</string>
+ <string name="toast_backup_ended" msgid="3818080769548726424">"Rezervna kopija je napravljena"</string>
+ <string name="toast_restore_started" msgid="7881679218971277385">"Pokretanje vraćanja..."</string>
+ <string name="toast_restore_ended" msgid="1764041639199696132">"Vraćanje je završeno"</string>
+ <string name="toast_timeout" msgid="5276598587087626877">"Vreme za radnju je isteklo"</string>
+</resources>
diff --git a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
index ac20aed..23688ae 100644
--- a/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-zh-rCN/strings.xml
@@ -18,10 +18,10 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"完全备份"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"完全还原"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面计算机。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"系统请求将所有数据完整备份至已连接的桌面设备。允许此操作吗?\n\n如果您本人未要求备份,请阻止该操作。"</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"备份我的数据"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"不备份"</string>
- <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面计算机完整还原所有数据。允许此操作吗?\n\n如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
+ <string name="restore_confirm_text" msgid="7499866728030461776">"系统请求从连接的桌面设备完整还原所有数据。允许此操作吗?\n\n如果您本人未要求还原,请阻止该操作。该操作会覆盖设备上当前的所有数据!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"恢复我的数据"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"不恢复"</string>
<string name="current_password_text" msgid="8268189555578298067">"请在下方输入您的当前备份密码:"</string>
diff --git a/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml b/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..fb05a9ed
--- /dev/null
+++ b/packages/CaptivePortalLogin/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
+ <string name="action_use_network" msgid="6076184727448466030">"Koristi ovu mrežu takvu kakva je"</string>
+ <string name="action_do_not_use_network" msgid="4577366536956516683">"Ne koristi ovu mrežu"</string>
+ <string name="action_bar_label" msgid="917235635415966620">"Prijavi me na mrežu"</string>
+ <string name="ssl_error_warning" msgid="6653188881418638872">"Mreža kojoj pokušavate da se pridružite ima bezbednosnih problema."</string>
+ <string name="ssl_error_example" msgid="647898534624078900">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
+ <string name="ssl_error_continue" msgid="6492718244923937110">"Ipak nastavi preko pregledača"</string>
+</resources>
diff --git a/core/java/com/android/internal/view/IDropPermissionHolder.aidl b/packages/DefaultContainerService/res/values-b+sr+Latn/strings.xml
similarity index 61%
copy from core/java/com/android/internal/view/IDropPermissionHolder.aidl
copy to packages/DefaultContainerService/res/values-b+sr+Latn/strings.xml
index e60ab0e..a0e1734 100644
--- a/core/java/com/android/internal/view/IDropPermissionHolder.aidl
+++ b/packages/DefaultContainerService/res/values-b+sr+Latn/strings.xml
@@ -1,5 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
/*
-** Copyright 2015, The Android Open Source Project
+**
+** Copyright 2008, The Android Open 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,14 +16,9 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+ -->
-package com.android.internal.view;
-
-/**
- * Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
- * contained in DragEvent.
- */
-interface IDropPermissionHolder {
- void grant();
- void revoke();
-}
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="service_name" msgid="4841491635055379553">"Pomoćnik za pristup paketu"</string>
+</resources>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 8cc79a4c..5e634a4 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -40,7 +40,7 @@
<activity
android:name=".DownloadsActivity"
- android:theme="@style/DocumentsFullScreenTheme"
+ android:theme="@style/DocumentsTheme"
android:label="@string/downloads_label"
android:icon="@drawable/ic_doc_text">
<intent-filter>
@@ -64,7 +64,7 @@
<activity
android:name=".FilesActivity"
- android:theme="@style/DocumentsFullScreenTheme"
+ android:theme="@style/DocumentsTheme"
android:icon="@drawable/ic_files_app"
android:label="@string/files_label"
android:documentLaunchMode="intoExisting">
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 2b21c12..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index ed3ee45..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 1a3ebc47..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 3086a69..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index b86f0f7..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 9d0988d..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 6c31360..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 1450ff0..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 4ad54bb..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 7f7c636..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
deleted file mode 100644
index d867847..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 5459767..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 0cbd992..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index db46702..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index b9f7af5..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 1218c2f..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 46d755f..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 933570b..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 30cea25..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 67b60de..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 65e42aa..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
deleted file mode 100644
index ac27eea..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index a4add51..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index a9a7f20..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index 26beb79..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index ed9cab7..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 451d287..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 7bc02c9..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index de39cd4..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index c3eb845..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 97f6e507..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
deleted file mode 100644
index b2f043f..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 483d7fb..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 2941b8a..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index d3ac072..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index a43f902..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index c572cd1..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 7ae671b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index a5ebd51..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 89ac434..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 855c44b..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 1de8292..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 4203d35..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 41558f2..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index e190c4d..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index fabc8c3..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index d8ba6e0..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 1b5111a..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index e7b7460..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 3183bfc..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 9a4e844..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 96d5721..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 23a1302..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index b0811f1..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 5f1f537..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 8083584..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 898e26a..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 2e9c667..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 56951c3..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index 08ed9f0..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index cd64e56..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index 0bc40de..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 00b8a8b7..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index 60f59f5..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 6006b12..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7926188..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index e65d74c..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index 7d32801..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index d528708..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index 274c524..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 6053b0a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index 78ee13b..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index dcf9cc2..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 74fbbbc..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index 11a219a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 9a461c9..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9a67956..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 853aa8c..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 84ae9ae..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 111439e..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index b876f86..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 7cf656a..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index acc3d7b..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 5236774..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
deleted file mode 100644
index d2dd494..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
deleted file mode 100644
index 4f935bf..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
deleted file mode 100644
index 7499cbc..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
deleted file mode 100644
index ca12928..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
deleted file mode 100644
index c4afa37..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
deleted file mode 100644
index 0b0aa04..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
deleted file mode 100644
index ebd0535..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
deleted file mode 100644
index 29cdbb7..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
deleted file mode 100644
index ca349b6..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
deleted file mode 100644
index 02249d2..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
deleted file mode 100644
index 469b911..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
deleted file mode 100644
index ef479c3..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
deleted file mode 100644
index 3168d6f..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
deleted file mode 100644
index 9bb4d66..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
deleted file mode 100644
index 88ba9ad..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
deleted file mode 100644
index 5fe18da..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
deleted file mode 100644
index 1d05f6f..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
deleted file mode 100644
index c2308fe..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
deleted file mode 100644
index 9a173be..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
deleted file mode 100644
index a564f5a..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index c7daa2a..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_album.xml b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
index e7965e6..1ce3f02 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_album.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_album.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_album_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm0 14.5c-2.49 0,-4.5,-2.01,-4.5,-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5,-2.01 4.5,-4.5 4.5zm0,-5.5c-.55 0,-1 .45,-1 1s.45 1 1 1 1,-.45 1,-1,-.45,-1,-1,-1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
index 4f8f06e..197445e 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_apk_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h1c.55 0 1,-.45 1,-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0,-1.5.67,-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5v-7c0,-.83,-.67,-1.5,-1.5,-1.5zm-4.97,-5.84l1.3,-1.3c.2,-.2.2,-.51 0,-.71,-.2,-.2,-.51,-.2,-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0,-1.86.23,-2.66.63L7.85.15c-.2,-.2,-.51,-.2,-.71 0,-.2.2,-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0,-1.99,-.97,-3.75,-2.47,-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
index cf18b4f..454eea3 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_audio_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM7.2 18c-.66 0,-1.2,-.54,-1.2,-1.2V12c0,-3.31 2.69,-6 6,-6s6 2.69 6 6v4.8c0 .66,-.54 1.2,-1.2 1.2H14v-4h2v-2c0,-2.21,-1.79,-4,-4,-4s-4 1.79,-4 4v2h2v4H7.2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
index c28ed4f..b99baf6 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_certificate_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M17.81 4.47c-.08 0,-.16,-.02,-.23,-.06C15.66 3.42 14 3 12.01 3c-1.98 0,-3.86.47,-5.57 1.41,-.24.13,-.54.04,-.68,-.2,-.13,-.24,-.04,-.55.2,-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67,-.09.18,-.26.28,-.44.28zM3.5 9.72c-.1 0,-.2,-.03,-.29,-.09,-.23,-.16,-.28,-.47,-.12,-.7.99,-1.4 2.25,-2.5 3.75,-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54,-.12.7,-.23.16,-.54.11,-.7,-.12,-.9,-1.26,-2.04,-2.25,-3.39,-2.94,-2.87,-1.47,-6.54,-1.47,-9.4.01,-1.36.7,-2.5 1.7,-3.4 2.96,-.08.14,-.23.21,-.39.21zm6.25 12.07c-.13 0,-.26,-.05,-.35,-.15,-.87,-.87,-1.34,-1.43,-2.01,-2.64,-.69,-1.23,-1.05,-2.73,-1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66 2.42 5.66 5.39c0 .28,-.22.5,-.5.5s-.5,-.22,-.5,-.5c0,-2.42,-2.09,-4.39,-4.66,-4.39,-2.57 0,-4.66 1.97,-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71,-.11.1,-.24.15,-.37.15zm7.17,-1.85c-1.19 0,-2.24,-.3,-3.1,-.89,-1.49,-1.01,-2.38,-2.65,-2.38,-4.39 0,-.28.22,-.5.5,-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64,-.03 1.04,-.1.27,-.05.53.13.58.41.05.27,-.13.53,-.41.58,-.57.11,-1.07.12,-1.21.12zM14.91 22c-.04 0,-.09,-.01,-.13,-.02,-1.59,-.44,-2.63,-1.03,-3.72,-2.1,-1.4,-1.39,-2.17,-3.24,-2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08,-.87 2.08,-1.94c0,-3.77,-3.25,-6.83,-7.25,-6.83,-2.84 0,-5.44 1.58,-6.61 4.03,-.39.81,-.59 1.76,-.59 2.8 0 .78.07 2.01.67 3.61.1.26,-.03.55,-.29.64,-.26.1,-.55,-.04,-.64,-.29,-.49,-1.31,-.73,-2.61,-.73,-3.96 0,-1.2.23,-2.29.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62,-1.38 2.94,-3.08 2.94s-3.08,-1.32,-3.08,-2.94c0,-1.07,-.93,-1.94,-2.08,-1.94s-2.08.87,-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61,-.05.23,-.26.38,-.47.38z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
index 0de721a9..ea1c464 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_codes_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M9.4 16.6L4.8 12l4.6,-4.6L8 6l-6 6 6 6 1.4,-1.4zm5.2 0l4.6,-4.6,-4.6,-4.6L16 6l6 6,-6 6,-1.4,-1.4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
index a49cfa4..e0eb669 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_compressed_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-5 6h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2v2zm0 8h-2v-2h-2v-2h2v2h2v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
index bf550cb..a77cb6b 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_contact_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M19 3H5c-1.11 0,-2 .89,-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.11,-.9,-2,-2,-2zm-7 3c1.65 0 3 1.35 3 3 0 1.66,-1.35 3,-3 3s-3,-1.34,-3,-3c0,-1.65 1.35,-3 3,-3zm6 12H6v-1c0,-2 4,-3.1 6,-3.1s6 1.1 6 3.1v1z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/DocumentsUI/res/drawable/ic_doc_document.xml
similarity index 73%
rename from packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
rename to packages/DocumentsUI/res/drawable/ic_doc_document.xml
index f11b690..29251ad 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_document.xml
@@ -14,11 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF0000FF"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+ android:fillColor="#FF4883F3"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-1.99 6H7V7h10.01v2zm0 4H7v-2h10.01v2zm-3 4H7v-2h7.01v2z"/>
</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_event.xml b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
index 25cf0f3..113f079 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_event.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_event.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_event_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0,-1.99.9,-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2h-1V1h-2zm3 18H5V8h14v11z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
index 3354725..3ed27e1 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_excel_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF16A765"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-2.8 14h-2L12 13.2 9.8 17h-2l3.2,-5,-3.2,-5h2l2.2 3.8L14.2 7h2L13 12l3.2 5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
index 73de60e..dcbce01 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_folder_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_font.xml b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
index c74cb9c..4c13d71 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_font.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_font.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_font_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0,-2 .9,-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4c0,-1.1,-.9,-2,-2,-2zm-4.05 16.5l-1.14,-3H9.17l-1.12 3H5.96l5.11,-13h1.86l5.11 13h-2.09z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
index a4ee29d..006dfba 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_generic_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M6 2c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6H6zm7 7V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_image.xml b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
index 9d4c359..23953f7 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_image.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_image.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_image_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M21 19V5c0,-1.1,-.9,-2,-2,-2H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5,-4.5z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
index 5c37498..b2d0193 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_pdf_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-9.5 8.5c0 .83,-.67 1.5,-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10,-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83,-.67 1.5,-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
index f0a6c39..aa5bfc8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_powerpoint_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFFF7537"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM9.8 13.4V17H8V7h4.3c1.53 0 2.15.3 2.8.89.65.59.9 1.37.9 2.34 0 1.02,-.26 1.8,-.9 2.35s-1.3.82,-2.8.82H9.8zm0,-1.4V8.4h2.3c.66 0 1.17.25 1.5.6.33.35.5.72.5 1.25 0 .55,-.18.95,-.5 1.25,-.32.31,-.7.5,-1.38.5H9.8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
index a14f866..7937bc1 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_presentation_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFF4B400"
+ android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2v14c0 1.1.89 2 1.99 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 13H5V8h14v8z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
index 40f2515..1663c0a 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_spreadsheet_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF16A765"
+ android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2L3 8v11c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 8h-8v8H9v-8H5V9h4V5h2v4h8v2z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_text.xml b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
index ffa9e70..7fc04e8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_text.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_text.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_text_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M14 2H6c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6zm2 16H8v-2h8v2zm0,-4H8v-2h8v2zm-3,-5V3.5L18.5 9H13z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
index 2d048c2..ad4dae8 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_video.xml
@@ -1,5 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_video_am_alpha"
- android:tint="?android:attr/colorControlNormal"
- android:autoMirrored="true" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FFDB4437"
+ android:pathData="M18 4l2 4h-3l-2,-4h-2l2 4h-3l-2,-4H8l2 4H7L5 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4h-4z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_doc_word.xml b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
index afcc533..7a3a0ec 100644
--- a/packages/DocumentsUI/res/drawable/ic_doc_word.xml
+++ b/packages/DocumentsUI/res/drawable/ic_doc_word.xml
@@ -1,4 +1,24 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_doc_word_alpha"
- android:tint="?android:attr/colorControlNormal" />
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF4883F3"
+ android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-3.5 14H14l-2,-7.5,-2 7.5H8.5L6.1 7h1.7l1.54 7.51L11.3 7h1.4l1.97 7.51L16.2 7h1.7l-2.4 10z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml b/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
deleted file mode 100644
index 27cfa81d..0000000
--- a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_root_sdcard_alpha"
- android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top.xml b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
similarity index 79%
rename from packages/SystemUI/res/drawable/vector_drawable_place_top.xml
rename to packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
index 92e01af..3021b16 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_top.xml
+++ b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
@@ -14,11 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
- android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/>
+ android:pathData="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/>
</vector>
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
new file mode 100644
index 0000000..c17b4c8
--- /dev/null
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/grid_item_margin"
+ android:background="@color/item_doc_background"
+ android:elevation="5dp"
+ android:focusable="true">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp">
+
+ <ImageView
+ android:src="@drawable/ic_doc_folder"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerInside"
+ android:contentDescription="@null"/>
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="middle"
+ android:textAlignment="viewStart"
+ android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+ android:textColor="@*android:color/primary_text_default_material_light" />
+
+ </LinearLayout>
+
+ <!-- An overlay that draws the item border when it is focused. -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@null"
+ android:background="@drawable/item_doc_grid_border"
+ android:duplicateParentState="true" />
+
+</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index dcd5cfd..3c796bd 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -19,6 +19,7 @@
android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
+ android:elevation="5dp"
android:focusable="true">
<!-- Main item thumbnail. Comprised of two overlapping images, the
@@ -39,9 +40,10 @@
<com.android.documentsui.GridItemThumbnail
android:id="@+id/icon_mime"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scaleType="centerInside"
+ android:layout_width="@dimen/icon_size"
+ android:layout_height="@dimen/icon_size"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter"
android:contentDescription="@null" />
</FrameLayout>
diff --git a/packages/DocumentsUI/res/values-sw720dp/layouts.xml b/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
similarity index 64%
rename from packages/DocumentsUI/res/values-sw720dp/layouts.xml
rename to packages/DocumentsUI/res/values-b+sr+Latn/config.xml
index 7d28f9c..843a8aa 100644
--- a/packages/DocumentsUI/res/values-sw720dp/layouts.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/config.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 The Android Open 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,8 +12,9 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--->
+ -->
-<resources>
- <item name="docs_activity" type="layout">@layout/fixed_layout</item>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="trusted_quick_viewer_package" msgid="3354383993907861267"></string>
</resources>
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..feace71
--- /dev/null
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <string name="app_label" msgid="2783841764617238354">"Dokumenti"</string>
+ <string name="files_label" msgid="6051402950202690279">"Datoteke"</string>
+ <string name="downloads_label" msgid="959113951084633612">"Preuzimanja"</string>
+ <string name="title_open" msgid="4353228937663917801">"Otvori sa"</string>
+ <string name="title_save" msgid="2433679664882857999">"Sačuvaj u"</string>
+ <string name="menu_create_dir" msgid="2547620241173881754">"Novi direktorijum"</string>
+ <string name="menu_grid" msgid="6878021334497835259">"Prikaz mreže"</string>
+ <string name="menu_list" msgid="7279285939892417279">"Prikaz liste"</string>
+ <string name="menu_sort" msgid="7677740407158414452">"Sortiraj prema"</string>
+ <string name="menu_search" msgid="3816712084502856974">"Pretraži"</string>
+ <string name="menu_settings" msgid="6008033148948428823">"Podešavanja"</string>
+ <string name="menu_open" msgid="432922957274920903">"Otvori"</string>
+ <string name="menu_save" msgid="2394743337684426338">"Sačuvaj"</string>
+ <string name="menu_share" msgid="3075149983979628146">"Deli"</string>
+ <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
+ <string name="menu_select_all" msgid="8323579667348729928">"Izaberi sve"</string>
+ <string name="menu_copy" msgid="3612326052677229148">"Kopiraj na..."</string>
+ <string name="menu_move" msgid="1828090633118079817">"Premesti u..."</string>
+ <string name="menu_new_window" msgid="1226032889278727538">"Novi prozor"</string>
+ <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string>
+ <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Nalepi"</string>
+ <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Prikaži internu memoriju"</string>
+ <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Prikaži SD karticu"</string>
+ <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sakrij internu memoriju"</string>
+ <string name="menu_advanced_hide" product="default" msgid="4845869969015718848">"Sakrij SD karticu"</string>
+ <string name="menu_file_size_show" msgid="3240323619260823076">"Prikaži veličinu datoteke"</string>
+ <string name="menu_file_size_hide" msgid="8881975928502581042">"Sakrij veličinu datoteke"</string>
+ <string name="button_select" msgid="527196987259139214">"Izaberi"</string>
+ <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
+ <string name="button_move" msgid="2202666023104202232">"Premesti"</string>
+ <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string>
+ <string name="button_retry" msgid="4392027584153752797">"Pokušaj ponovo"</string>
+ <string name="sort_name" msgid="9183560467917256779">"Prema imenu"</string>
+ <string name="sort_date" msgid="586080032956151448">"Prema datumu izmene"</string>
+ <string name="sort_size" msgid="3350681319735474741">"Prema veličini"</string>
+ <string name="drawer_open" msgid="4545466532430226949">"Prikaži osnovne elemente"</string>
+ <string name="drawer_close" msgid="7602734368552123318">"Sakrij osnovne elemente"</string>
+ <string name="save_error" msgid="6167009778003223664">"Čuvanje dokumenta nije uspelo"</string>
+ <string name="create_error" msgid="3735649141335444215">"Direktorijum nije napravljen"</string>
+ <string name="query_error" msgid="1222448261663503501">"Slanje upita za dokumente nije uspelo"</string>
+ <string name="root_recent" msgid="4470053704320518133">"Nedavno"</string>
+ <string name="root_available_bytes" msgid="8568452858617033281">"Slobodno je <xliff:g id="SIZE">%1$s</xliff:g>"</string>
+ <string name="root_type_service" msgid="2178854894416775409">"Usluge skladištenja"</string>
+ <string name="root_type_shortcut" msgid="3318760609471618093">"Prečice"</string>
+ <string name="root_type_device" msgid="7121342474653483538">"Uređaji"</string>
+ <string name="root_type_apps" msgid="8838065367985945189">"Još aplikacija"</string>
+ <string name="empty" msgid="7858882803708117596">"Nema stavki"</string>
+ <string name="toast_no_application" msgid="1339885974067891667">"Nije moguće otvoriti datoteku"</string>
+ <string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
+ <string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
+ <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
+ <string name="move_notification_title" msgid="6193835179777284805">"Datoteke se premeštaju"</string>
+ <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
+ <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+ <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+ <item quantity="few">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+ <item quantity="other">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+ </plurals>
+ <plurals name="move_begin" formatted="false" msgid="8430330882138871643">
+ <item quantity="one">Premešta se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+ <item quantity="few">Premeštaju se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+ <item quantity="other">Premešta se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+ </plurals>
+ <plurals name="deleting" formatted="false" msgid="5054338566802559411">
+ <item quantity="one">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+ <item quantity="few">Brišu se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+ <item quantity="other">Briše se <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+ </plurals>
+ <string name="undo" msgid="7905788502491742328">"Opozovi"</string>
+ <string name="copy_preparing" msgid="3896202461003039386">"Priprema se kopiranje…"</string>
+ <string name="move_preparing" msgid="2772219441375531410">"Priprema se premeštanje..."</string>
+ <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261">
+ <item quantity="one">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku</item>
+ <item quantity="few">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+ <item quantity="other">Nismo uspeli da kopiramo <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
+ </plurals>
+ <plurals name="move_error_notification_title" formatted="false" msgid="2779299594174898891">
+ <item quantity="one">Nije uspelo premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+ <item quantity="few">Nije uspelo premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke</item>
+ <item quantity="other">Nije uspelo premeštanje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka</item>
+ </plurals>
+ <string name="notification_touch_for_details" msgid="4483108577842961665">"Dodirnite da biste videli detalje"</string>
+ <string name="retry" msgid="7564024179122207376">"Pokušaj ponovo"</string>
+ <string name="copy_failure_alert_content" msgid="3715575000297709082">"Sledeće datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <string name="move_failure_alert_content" msgid="7151140279020481180">"Ove datoteke nisu premeštene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
+ <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
+ <item quantity="one">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku u privremenu memoriju.</item>
+ <item quantity="few">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke u privremenu memoriju.</item>
+ <item quantity="other">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka u privremenu memoriju.</item>
+ </plurals>
+ <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Izabrane datoteke ne mogu da se nalepe na ovoj lokaciji."</string>
+</resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 2d8be1b..51cb774 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -26,7 +26,7 @@
<string name="menu_list" msgid="7279285939892417279">"Приказ на список"</string>
<string name="menu_sort" msgid="7677740407158414452">"Подреди по"</string>
<string name="menu_search" msgid="3816712084502856974">"Пребарај"</string>
- <string name="menu_settings" msgid="6008033148948428823">"Подесувања"</string>
+ <string name="menu_settings" msgid="6008033148948428823">"Поставки"</string>
<string name="menu_open" msgid="432922957274920903">"Отвори"</string>
<string name="menu_save" msgid="2394743337684426338">"Зачувај"</string>
<string name="menu_share" msgid="3075149983979628146">"Сподели"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b522e0a..c303e0c 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -97,8 +97,8 @@
<string name="copy_failure_alert_content" msgid="3715575000297709082">"Faili hizi hazikunakiliwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<string name="move_failure_alert_content" msgid="7151140279020481180">"Faili hizi hazikuhamishwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
<plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
- <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubaoklipu.</item>
- <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubaoklipu.</item>
+ <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
+ <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
</plurals>
<string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Haiwezi kubandika faili zilizochaguliwa katika eneo hili."</string>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/dimens.xml b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
index f393d88..2488fa2 100644
--- a/packages/DocumentsUI/res/values-sw720dp/dimens.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/dimens.xml
@@ -15,12 +15,7 @@
-->
<resources>
- <bool name="show_as_dialog">true</bool>
-
- <item type="dimen" name="dialog_width">85%</item>
-
<dimen name="grid_padding_horiz">16dp</dimen>
<dimen name="grid_padding_vert">16dp</dimen>
- <dimen name="grid_item_margin">8dp</dimen>
</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
deleted file mode 100644
index a8dcbb0..0000000
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android">
-
- <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.Dialog">
- <!-- We do not specify width of window here because the max size of
- floating window specified by windowFixedWidthis is limited. -->
- <item name="*android:windowFixedHeightMajor">80%</item>
- <item name="*android:windowFixedHeightMinor">90%</item>
- </style>
-
-</resources>
diff --git a/packages/DocumentsUI/res/values/attrs.xml b/packages/DocumentsUI/res/values/attrs.xml
index 0afc3a2..9e13001 100644
--- a/packages/DocumentsUI/res/values/attrs.xml
+++ b/packages/DocumentsUI/res/values/attrs.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
<resources>
- <declare-styleable name="DocumentsBaseTheme">
+ <declare-styleable name="DocumentsTheme">
<attr name="colorActionMode" format="color"/>
</declare-styleable>
</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index f94a00e..060871d 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -35,7 +35,6 @@
<dimen name="list_divider_inset">72dp</dimen>
<bool name="list_divider_inset_left">true</bool>
- <bool name="show_as_dialog">false</bool>
<bool name="always_show_summary">false</bool>
<dimen name="dir_elevation">8dp</dimen>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 6712e2d..d14631d 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -16,31 +16,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar" />
<style name="ActionBarTheme" parent="@*android:style/ThemeOverlay.Material.Dark.ActionBar" />
<style name="ActionBarPopupTheme" parent="@*android:style/ThemeOverlay.Material.Light" />
- <style name="DocumentsTheme" parent="@style/DocumentsBaseTheme">
- <item name="actionBarWidgetTheme">@null</item>
- <item name="actionBarTheme">@style/ActionBarTheme</item>
- <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
-
- <item name="android:windowBackground">@color/window_background</item>
- <item name="android:colorPrimaryDark">@color/primary_dark</item>
- <item name="android:colorPrimary">@color/primary</item>
- <item name="android:colorAccent">@color/accent</item>
- <item name="colorActionMode">@color/action_mode</item>
-
- <item name="android:listDivider">@*android:drawable/list_divider_material</item>
-
- <item name="android:windowActionBar">false</item>
- <item name="android:windowActionModeOverlay">true</item>
- <item name="android:windowNoTitle">true</item>
-
- <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
- </style>
-
- <style name="DocumentsFullScreenTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
+ <style name="DocumentsTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
<item name="actionBarWidgetTheme">@null</item>
<item name="actionBarTheme">@style/ActionBarTheme</item>
<item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index edf384e..a241667 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -39,7 +39,6 @@
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.util.Log;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -60,6 +59,7 @@
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
@@ -85,7 +85,7 @@
private int mLayoutId;
private DirectoryContainerView mDirectoryContainer;
- public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
+ public abstract void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings);
public abstract void onDocumentsPicked(List<DocumentInfo> docs);
abstract void onTaskFinished(Uri... uris);
@@ -111,6 +111,13 @@
setContentView(mLayoutId);
mRoots = DocumentsApplication.getRootsCache(this);
+ mRoots.setOnCacheUpdateListener(
+ new RootsCache.OnCacheUpdateListener() {
+ @Override
+ public void onCacheUpdate() {
+ new HandleRootsChangedTask().execute(getCurrentRoot());
+ }
+ });
mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
mSearchManager = new SearchManager();
@@ -203,7 +210,25 @@
if (mRoots.isRecentsRoot(root)) {
onCurrentDirectoryChanged(ANIM_SIDE);
} else {
- new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory());
+ new PickRootTask(root, true).executeOnExecutor(getExecutorForCurrentDirectory());
+ }
+ }
+
+ void setRoot(RootInfo root) {
+ // Clear entire backstack and start in new root
+ mState.stack.root = root;
+ mState.stack.clear();
+ mState.stackTouched = false;
+
+ mSearchManager.update(root);
+
+ // Recents is always in memory, so we just load it directly.
+ // Otherwise we delegate loading data from disk to a task
+ // to ensure a responsive ui.
+ if (mRoots.isRecentsRoot(root)) {
+ onCurrentDirectoryChanged(ANIM_SIDE);
+ } else {
+ new PickRootTask(root, false).executeOnExecutor(getExecutorForCurrentDirectory());
}
}
@@ -483,9 +508,11 @@
final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> {
private RootInfo mRoot;
+ private boolean mTouched;
- public PickRootTask(RootInfo root) {
+ public PickRootTask(RootInfo root, boolean touched) {
mRoot = root;
+ mTouched = touched;
}
@Override
@@ -504,7 +531,7 @@
protected void onPostExecute(DocumentInfo result) {
if (result != null) {
mState.stack.push(result);
- mState.stackTouched = true;
+ mState.stackTouched = mTouched;
onCurrentDirectoryChanged(ANIM_SIDE);
}
}
@@ -591,6 +618,34 @@
}
}
+ final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> {
+ @Override
+ protected RootInfo doInBackground(RootInfo... roots) {
+ Preconditions.checkArgument(roots.length == 1);
+ final RootInfo currentRoot = roots[0];
+ final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking();
+ RootInfo homeRoot = null;
+ for (final RootInfo root : cachedRoots) {
+ if (root.isHome()) {
+ homeRoot = root;
+ }
+ if (root.getUri().equals(currentRoot.getUri())) {
+ // We don't need to change the current root as the current root was not removed.
+ return null;
+ }
+ }
+ Preconditions.checkNotNull(homeRoot);
+ return homeRoot;
+ }
+
+ @Override
+ protected void onPostExecute(RootInfo result) {
+ if (result != null) {
+ setRoot(result);
+ }
+ }
+ }
+
final class ItemSelectedListener implements OnItemSelectedListener {
boolean mIgnoreNextNavigation;
@@ -755,11 +810,19 @@
* search currently.
*/
boolean cancelSearch() {
+ boolean collapsed = false;
+ boolean closed = false;
+
if (mActionBar.hasExpandedActionView()) {
mActionBar.collapseActionView();
- return true;
+ collapsed = true;
}
- return false;
+
+ if (isExpanded() || isSearching()) {
+ onClose();
+ closed = true;
+ }
+ return collapsed || closed;
}
boolean isSearching() {
@@ -826,7 +889,7 @@
* Interface providing access to current view of documents
* even when all documents are not homed to the same parent.
*/
- public interface DocumentContext {
+ public interface SiblingProvider {
/**
* Returns the cursor for the selected document. The cursor can be used to retrieve
* details about a document and its siblings.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 6d947d1..34614b4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -45,6 +45,7 @@
import android.support.design.widget.Snackbar;
import android.text.format.DateUtils;
import android.util.Log;
+import android.webkit.MimeTypeMap;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
@@ -463,9 +464,10 @@
* @param srcInfo DocumentInfos for the documents to copy.
* @param dstDirInfo The destination directory.
* @param mode The transfer mode (copy or move).
+ * @return True on success, false on failure.
* @throws RemoteException
*/
- private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
+ private boolean copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
throws RemoteException {
// When copying within the same provider, try to use optimized copying and moving.
// If not supported, then fallback to byte-by-byte copy/move.
@@ -477,7 +479,7 @@
dstDirInfo.derivedUri) == null) {
mFailedFiles.add(srcInfo);
}
- return;
+ return false;
}
break;
case TRANSFER_MODE_MOVE:
@@ -486,7 +488,7 @@
dstDirInfo.derivedUri) == null) {
mFailedFiles.add(srcInfo);
}
- return;
+ return false;
}
break;
default:
@@ -494,47 +496,77 @@
}
}
+ final String dstMimeType;
+ final String dstDisplayName;
+
+ // If the file is virtual, but can be converted to another format, then try to copy it
+ // as such format. Also, append an extension for the target mime type (if known).
+ if (srcInfo.isVirtualDocument()) {
+ final String[] streamTypes = getContentResolver().getStreamTypes(
+ srcInfo.derivedUri, "*/*");
+ if (streamTypes != null && streamTypes.length > 0) {
+ dstMimeType = streamTypes[0];
+ final String extension = MimeTypeMap.getSingleton().
+ getExtensionFromMimeType(dstMimeType);
+ dstDisplayName = srcInfo.displayName +
+ (extension != null ? "." + extension : srcInfo.displayName);
+ } else {
+ // The virtual file is not available as any alternative streamable format.
+ // TODO: Log failures. b/26192412
+ mFailedFiles.add(srcInfo);
+ return false;
+ }
+ } else {
+ dstMimeType = srcInfo.mimeType;
+ dstDisplayName = srcInfo.displayName;
+ }
+
// Create the target document (either a file or a directory), then copy recursively the
// contents (bytes or children).
- final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
- srcInfo.mimeType, srcInfo.displayName);
+ final Uri dstUri = DocumentsContract.createDocument(mDstClient,
+ dstDirInfo.derivedUri, dstMimeType, dstDisplayName);
if (dstUri == null) {
// If this is a directory, the entire subdir will not be copied over.
mFailedFiles.add(srcInfo);
- return;
+ return false;
}
DocumentInfo dstInfo = null;
try {
- final DocumentInfo dstDocInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
+ dstInfo = DocumentInfo.fromUri(getContentResolver(), dstUri);
} catch (FileNotFoundException e) {
mFailedFiles.add(srcInfo);
- return;
+ return false;
}
+ final boolean success;
if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
- copyDirectoryHelper(srcInfo, dstInfo, mode);
+ success = copyDirectoryHelper(srcInfo, dstInfo, mode);
} else {
- copyFileHelper(srcInfo, dstInfo, mode);
+ success = copyFileHelper(srcInfo, dstInfo, dstMimeType, mode);
}
- if (mode == TRANSFER_MODE_MOVE) {
+ if (mode == TRANSFER_MODE_MOVE && success) {
+ // This is racey. We should make sure that we never delete a directory after
+ // it changed, so we don't remove a file which had not been copied earlier
+ // to the target location.
try {
DocumentsContract.deleteDocument(mSrcClient, srcInfo.derivedUri);
} catch (RemoteException e) {
- // RemoteExceptions usually signal that the connection is dead, so there's no
- // point attempting to continue. Propagate the exception up so the copy job is
- // cancelled.
- Log.w(TAG, "Failed to clean up after move: " + srcInfo.derivedUri, e);
+ Log.w(TAG, "Failed to delete source after moving: " + srcInfo.derivedUri, e);
throw e;
}
}
+
+ return success;
}
/**
* Returns true if {@code doc} is a descendant of {@code parentDoc}.
+ * @throws RemoteException
*/
- boolean isDescendentOf(DocumentInfo doc, DocumentInfo parentDoc) throws RemoteException {
+ boolean isDescendentOf(DocumentInfo doc, DocumentInfo parentDoc)
+ throws RemoteException {
if (parentDoc.isDirectory() && doc.authority.equals(parentDoc.authority)) {
return DocumentsContract.isChildDocument(
mDstClient, doc.derivedUri, parentDoc.derivedUri);
@@ -549,9 +581,11 @@
* @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's
* contents, not the directory itself.
* @param dstDirInfo Info of the directory to copy to. Must be created beforehand.
+ * @return True on success, false if some of the children failed to copy.
* @throws RemoteException
*/
- private void copyDirectoryHelper(DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode)
+ private boolean copyDirectoryHelper(
+ DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode)
throws RemoteException {
// Recurse into directories. Copy children into the new subdirectory.
final String queryColumns[] = new String[] {
@@ -562,17 +596,22 @@
Document.COLUMN_FLAGS
};
Cursor cursor = null;
+ boolean success = true;
try {
// Iterate over srcs in the directory; copy to the destination directory.
+ final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirInfo.authority,
+ srcDirInfo.documentId);
+ cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
DocumentInfo srcInfo;
- cursor = mSrcClient.query(srcDirInfo.derivedUri, queryColumns, null, null, null);
while (cursor.moveToNext()) {
srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority);
- copy(srcInfo, dstDirInfo, mode);
+ success &= copy(srcInfo, dstDirInfo, mode);
}
} finally {
IoUtils.closeQuietly(cursor);
}
+
+ return success;
}
/**
@@ -580,10 +619,12 @@
*
* @param srcUriInfo Info of the file to copy from.
* @param dstUriInfo Info of the *file* to copy to. Must be created beforehand.
+ * @param mimeType Mime type for the target. Can be different than source for virtual files.
+ * @return True on success, false on error.
* @throws RemoteException
*/
- private void copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, int mode)
- throws RemoteException {
+ private boolean copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, String mimeType,
+ int mode) throws RemoteException {
// Copy an individual file.
CancellationSignal canceller = new CancellationSignal();
ParcelFileDescriptor srcFile = null;
@@ -591,45 +632,42 @@
InputStream src = null;
OutputStream dst = null;
- IOException copyError = null;
+ boolean success = true;
try {
- // If the file is virtual, but can be converted to another format, then try to copy it
- // as such format.
- if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) {
- final String[] streamTypes = mSrcClient.getStreamTypes(srcInfo.derivedUri, "*/*");
- if (streamTypes.length > 0) {
- // Pick the first streamable format.
- final AssetFileDescriptor srcFileAsAsset =
- mSrcClient.openTypedAssetFileDescriptor(
- srcInfo.derivedUri, streamTypes[0], null, canceller);
- srcFile = srcFileAsAsset.getParcelFileDescriptor();
- src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
- } else {
- // TODO: Log failures. b/26192412
- mFailedFiles.add(srcInfo);
- }
+ // If the file is virtual, then try to copy it as an alternative format.
+ if (srcInfo.isVirtualDocument()) {
+ final AssetFileDescriptor srcFileAsAsset =
+ mSrcClient.openTypedAssetFileDescriptor(
+ srcInfo.derivedUri, mimeType, null, canceller);
+ srcFile = srcFileAsAsset.getParcelFileDescriptor();
+ src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset);
} else {
srcFile = mSrcClient.openFile(srcInfo.derivedUri, "r", canceller);
src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
}
+
dstFile = mDstClient.openFile(dstInfo.derivedUri, "w", canceller);
dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
byte[] buffer = new byte[8192];
int len;
- while (!mIsCancelled && ((len = src.read(buffer)) != -1)) {
+ while ((len = src.read(buffer)) != -1) {
+ if (mIsCancelled) {
+ success = false;
+ break;
+ }
dst.write(buffer, 0, len);
makeProgress(len);
}
srcFile.checkError();
} catch (IOException e) {
- copyError = e;
+ success = false;
mFailedFiles.add(srcInfo);
if (dstFile != null) {
try {
- dstFile.closeWithError(copyError.getMessage());
+ dstFile.closeWithError(e.getMessage());
} catch (IOException closeError) {
Log.e(TAG, "Error closing destination", closeError);
}
@@ -640,18 +678,21 @@
IoUtils.closeQuietly(dst);
}
- if (copyError != null || mIsCancelled) {
+ if (!success) {
// Clean up half-copied files.
canceller.cancel();
try {
DocumentsContract.deleteDocument(mDstClient, dstInfo.derivedUri);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to clean up after copy error: " + dstInfo.derivedUri, e);
- // RemoteExceptions usually signal that the connection is dead, so there's no point
- // attempting to continue. Propagate the exception up so the copy job is cancelled.
+ // RemoteExceptions usually signal that the connection is dead, so there's no
+ // point attempting to continue. Propagate the exception up so the copy job is
+ // cancelled.
+ Log.w(TAG, "Failed to cleanup after copy error: " + srcInfo.derivedUri, e);
throw e;
}
}
+
+ return success;
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index b0bbec3..6719b23 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -114,11 +114,7 @@
if (userMode != State.MODE_UNKNOWN) {
result.mode = userMode;
} else {
- if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
- result.mode = State.MODE_GRID;
- } else {
- result.mode = State.MODE_LIST;
- }
+ result.mode = State.MODE_GRID;
}
if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
@@ -156,9 +152,6 @@
if (mType == DirectoryFragment.TYPE_SEARCH) {
// Filter directories out of search results, for now
cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES);
- } else {
- // Normal directories should have sorting applied
- cursor = new SortingCursorWrapper(cursor, result.sortOrder);
}
result.client = client;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8754f68..8ca2cfb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -19,8 +19,8 @@
import static com.android.documentsui.State.ACTION_CREATE;
import static com.android.documentsui.State.ACTION_GET_CONTENT;
import static com.android.documentsui.State.ACTION_OPEN;
-import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
import static com.android.documentsui.State.ACTION_OPEN_TREE;
+import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import android.app.Activity;
@@ -31,11 +31,9 @@
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
-import android.graphics.Point;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -46,7 +44,6 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.Spinner;
import android.widget.Toolbar;
@@ -65,8 +62,6 @@
private static final int CODE_FORWARD = 42;
private static final String TAG = "DocumentsActivity";
- private boolean mShowAsDialog;
-
private Toolbar mToolbar;
private Spinner mToolbarStack;
@@ -84,29 +79,8 @@
super.onCreate(icicle);
final Resources res = getResources();
- mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
- if (!mShowAsDialog) {
- setTheme(R.style.DocumentsFullScreenTheme);
- }
-
- if (mShowAsDialog) {
- mDrawer = DrawerController.createDummy();
-
- // Strongly define our horizontal dimension; we leave vertical as
- // WRAP_CONTENT so that system resizes us when IME is showing.
- final WindowManager.LayoutParams a = getWindow().getAttributes();
-
- final Point size = new Point();
- getWindowManager().getDefaultDisplay().getSize(size);
- a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
-
- getWindow().setAttributes(a);
-
- } else {
- mDrawer = DrawerController.create(this);
- }
-
+ mDrawer = DrawerController.create(this);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mStackAdapter = new StackAdapter();
@@ -268,15 +242,16 @@
}
}
- if (!mShowAsDialog && mDrawer.isUnlocked()) {
+ if (mDrawer.isUnlocked()) {
mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
mToolbar.setNavigationContentDescription(R.string.drawer_open);
- mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- setRootsDrawerOpen(true);
- }
- });
+ mToolbar.setNavigationOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setRootsDrawerOpen(true);
+ }
+ });
} else {
mToolbar.setNavigationIcon(null);
mToolbar.setNavigationContentDescription(R.string.drawer_open);
@@ -307,10 +282,7 @@
public boolean onCreateOptionsMenu(Menu menu) {
boolean showMenu = super.onCreateOptionsMenu(menu);
- // Most actions are visible when showing as dialog
- if (mShowAsDialog) {
- expandMenus(menu);
- }
+ expandMenus(menu);
return showMenu;
}
@@ -419,7 +391,7 @@
}
@Override
- public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+ public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
final FragmentManager fm = getFragmentManager();
if (doc.isContainer()) {
openContainerDocument(doc);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
index cccbbc8..b806ced 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
@@ -183,7 +183,7 @@
}
@Override
- public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+ public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
final FragmentManager fm = getFragmentManager();
if (doc.isContainer()) {
openContainerDocument(doc);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 0b6a09f..e308f3f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -89,53 +89,51 @@
RootsFragment.show(getFragmentManager(), null);
- if (mState.restored) {
- if (DEBUG) Log.d(TAG, "Restored instance for uri: " + getIntent().getData());
- onCurrentDirectoryChanged(ANIM_NONE);
- } else {
- Intent intent = getIntent();
- Uri uri = intent.getData();
+ final Intent intent = getIntent();
+ final Uri uri = intent.getData();
- if (DEBUG) Log.d(TAG, "Creating new instance for uri: " + uri);
+ if (mState.restored) {
+ if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
+ onCurrentDirectoryChanged(ANIM_NONE);
+ } else if (!mState.stack.isEmpty()) {
// If a non-empty stack is present in our state it was read (presumably)
// from EXTRA_STACK intent extra. In this case, we'll skip other means of
// loading or restoring the stack.
- if (!mState.stack.isEmpty()) {
- if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
- // When restoring from a stack, if a URI is present, it should only ever
- // be a launch URI. Launch URIs support sensible activity management, but
- // don't specify a real content target.
- checkState(uri == null || LauncherActivity.isLaunchUri(uri));
- onCurrentDirectoryChanged(ANIM_NONE);
- } else if (DocumentsContract.isRootUri(this, uri)) {
- if (DEBUG) Log.d(TAG, "Launching with root URI.");
- // If we've got a specific root to display, restore that root using a dedicated
- // authority. That way a misbehaving provider won't result in an ANR.
- new RestoreRootTask(uri).executeOnExecutor(
- ProviderExecutor.forAuthority(uri.getAuthority()));
- } else {
- if (DEBUG) Log.d(TAG, "Launching into Home directory.");
- // If all else fails, try to load "Home" directory.
- uri = DocumentsContract.buildHomeUri();
- new RestoreRootTask(uri).executeOnExecutor(
- ProviderExecutor.forAuthority(uri.getAuthority()));
- }
+ //
+ // When restoring from a stack, if a URI is present, it should only ever
+ // be a launch URI. Launch URIs support sensible activity management, but
+ // don't specify a real content target.
+ if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
+ checkState(uri == null || LauncherActivity.isLaunchUri(uri));
+ onCurrentDirectoryChanged(ANIM_NONE);
+ } else if (DocumentsContract.isRootUri(this, uri)) {
+ if (DEBUG) Log.d(TAG, "Launching with root URI.");
+ // If we've got a specific root to display, restore that root using a dedicated
+ // authority. That way a misbehaving provider won't result in an ANR.
+ new RestoreRootTask(uri).executeOnExecutor(
+ ProviderExecutor.forAuthority(uri.getAuthority()));
+ } else {
+ if (DEBUG) Log.d(TAG, "Launching into Home directory.");
+ // If all else fails, try to load "Home" directory.
+ final Uri homeUri = DocumentsContract.buildHomeUri();
+ new RestoreRootTask(homeUri).executeOnExecutor(
+ ProviderExecutor.forAuthority(homeUri.getAuthority()));
+ }
- // TODO: Ensure we're handling CopyService errors correctly across all activities.
- // Show a failure dialog if there was a failed operation.
- final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
- final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
- CopyService.TRANSFER_MODE_COPY);
- if (failure != 0) {
- final ArrayList<DocumentInfo> failedSrcList =
- intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
- FailureDialogFragment.show(
- getFragmentManager(),
- failure,
- failedSrcList,
- mState.stack,
- transferMode);
- }
+ final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
+ final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
+ CopyService.TRANSFER_MODE_COPY);
+ // DialogFragment takes care of restoring the dialog on configuration change.
+ // Only show it manually for the first time (icicle is null).
+ if (icicle == null && failure != 0) {
+ final ArrayList<DocumentInfo> failedSrcList =
+ intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
+ FailureDialogFragment.show(
+ getFragmentManager(),
+ failure,
+ failedSrcList,
+ mState.stack,
+ transferMode);
}
}
@@ -323,7 +321,7 @@
}
@Override
- public void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings) {
+ public void onDocumentPicked(DocumentInfo doc, @Nullable SiblingProvider siblings) {
if (doc.isContainer()) {
openContainerDocument(doc);
} else {
@@ -334,7 +332,7 @@
/**
* Launches an intent to view the specified document.
*/
- private void openDocument(DocumentInfo doc, @Nullable DocumentContext siblings) {
+ private void openDocument(DocumentInfo doc, @Nullable SiblingProvider siblings) {
Intent intent = null;
if (siblings != null) {
QuickViewIntentBuilder builder = new QuickViewIntentBuilder(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index a1213d2..c28fae8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -159,8 +159,8 @@
add("application/vnd.sun.xml.calc.template", icon);
add("application/x-kspread", icon);
- // Text
- icon = R.drawable.ic_doc_text;
+ // Document
+ icon = R.drawable.ic_doc_document;
add("application/vnd.oasis.opendocument.text", icon);
add("application/vnd.oasis.opendocument.text-master", icon);
add("application/vnd.oasis.opendocument.text-template", icon);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 605c530..5a80c39 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -34,7 +34,7 @@
import android.text.TextUtils;
import android.util.Log;
-import com.android.documentsui.BaseActivity.DocumentContext;
+import com.android.documentsui.BaseActivity.SiblingProvider;
import com.android.documentsui.model.DocumentInfo;
/**
@@ -43,7 +43,7 @@
final class QuickViewIntentBuilder {
private final DocumentInfo mDocument;
- private final DocumentContext mContext;
+ private final SiblingProvider mSiblings;
private final PackageManager mPkgManager;
private final Resources mResources;
@@ -55,12 +55,12 @@
PackageManager pkgManager,
Resources resources,
DocumentInfo doc,
- DocumentContext context) {
+ SiblingProvider siblings) {
mPkgManager = pkgManager;
mResources = resources;
mDocument = doc;
- mContext = context;
+ mSiblings = siblings;
}
/**
@@ -84,7 +84,7 @@
intent.setPackage(trustedPkg);
if (hasRegisteredHandler(intent)) {
// We have a trusted handler. Load all of the docs into the intent.
- Cursor cursor = mContext.getCursor();
+ Cursor cursor = mSiblings.getCursor();
for (int i = 0; i < cursor.getCount(); i++) {
onNextItem(i, cursor);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 4bd6ae6..0ee54e6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -233,12 +233,6 @@
final DirectoryResult result = new DirectoryResult();
result.sortOrder = SORT_ORDER_LAST_MODIFIED;
- // Hint to UI if we're still loading
- final Bundle extras = new Bundle();
- if (!allDone) {
- extras.putBoolean(DocumentsContract.EXTRA_LOADING, true);
- }
-
final Cursor merged;
if (cursors.size() > 0) {
merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
@@ -247,14 +241,13 @@
merged = new MatrixCursor(new String[0]);
}
- final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder) {
- @Override
- public Bundle getExtras() {
- return extras;
- }
- };
+ // Tell the UI if this is an in-progress result. When loading is complete, another update is
+ // sent with EXTRA_LOADING set to false.
+ Bundle extras = new Bundle();
+ extras.putBoolean(DocumentsContract.EXTRA_LOADING, !allDone);
+ merged.setExtras(extras);
- result.cursor = sorted;
+ result.cursor = merged;
return result;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 72ee6cbab..21e7566 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -63,6 +63,7 @@
private final Context mContext;
private final ContentObserver mObserver;
+ private OnCacheUpdateListener mCacheUpdateListener;
private final RootInfo mRecentsRoot = new RootInfo();
@@ -94,6 +95,10 @@
}
}
+ static interface OnCacheUpdateListener {
+ void onCacheUpdate();
+ }
+
/**
* Gather roots from all known storage providers.
*/
@@ -209,6 +214,13 @@
return null;
}
+ @Override
+ protected void onPostExecute(Void result) {
+ if (mCacheUpdateListener != null) {
+ mCacheUpdateListener.onCacheUpdate();
+ }
+ }
+
private void handleDocumentsProvider(ProviderInfo info) {
// Ignore stopped packages for now; we might query them
// later during UI interaction.
@@ -348,6 +360,10 @@
}
}
+ public void setOnCacheUpdateListener(OnCacheUpdateListener cacheUpdateListener) {
+ mCacheUpdateListener = cacheUpdateListener;
+ }
+
@VisibleForTesting
static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
final List<RootInfo> matching = new ArrayList<>();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 570c9bf..c3366c3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -17,6 +17,8 @@
package com.android.documentsui;
import android.content.Context;
+import android.text.format.DateUtils;
+import android.text.format.Time;
/** @hide */
public final class Shared {
@@ -40,4 +42,26 @@
public static final String getQuantityString(Context context, int resourceId, int quantity) {
return context.getResources().getQuantityString(resourceId, quantity, quantity);
}
+
+ public static String formatTime(Context context, long when) {
+ // TODO: DateUtils should make this easier
+ Time then = new Time();
+ then.set(when);
+ Time now = new Time();
+ now.setToNow();
+
+ int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
+ | DateUtils.FORMAT_ABBREV_ALL;
+
+ if (then.year != now.year) {
+ flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
+ } else if (then.yearDay != now.yearDay) {
+ flags |= DateUtils.FORMAT_SHOW_DATE;
+ } else {
+ flags |= DateUtils.FORMAT_SHOW_TIME;
+ }
+
+ return DateUtils.formatDateTime(context, when, flags);
+ }
+
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
deleted file mode 100644
index 6698ff1..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.documentsui;
-
-import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.model.DocumentInfo.getCursorLong;
-import static com.android.documentsui.model.DocumentInfo.getCursorString;
-
-import android.database.AbstractCursor;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.provider.DocumentsContract.Document;
-
-import com.android.documentsui.model.DocumentInfo;
-
-/**
- * Cursor wrapper that presents a sorted view of the underlying cursor. Handles
- * common {@link Document} sorting modes, such as ordering directories first.
- */
-public class SortingCursorWrapper extends AbstractCursor {
- private final Cursor mCursor;
-
- private final int[] mPosition;
- private final String[] mValueString;
- private final long[] mValueLong;
-
- public SortingCursorWrapper(Cursor cursor, int sortOrder) {
- mCursor = cursor;
-
- final int count = cursor.getCount();
- mPosition = new int[count];
- switch (sortOrder) {
- case SORT_ORDER_DISPLAY_NAME:
- mValueString = new String[count];
- mValueLong = null;
- break;
- case SORT_ORDER_LAST_MODIFIED:
- case SORT_ORDER_SIZE:
- mValueString = null;
- mValueLong = new long[count];
- break;
- default:
- throw new IllegalArgumentException();
- }
-
- cursor.moveToPosition(-1);
- for (int i = 0; i < count; i++) {
- cursor.moveToNext();
- mPosition[i] = i;
-
- switch (sortOrder) {
- case SORT_ORDER_DISPLAY_NAME:
- final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- final String displayName = getCursorString(
- cursor, Document.COLUMN_DISPLAY_NAME);
- if (Document.MIME_TYPE_DIR.equals(mimeType)) {
- mValueString[i] = DocumentInfo.DIR_PREFIX + displayName;
- } else {
- mValueString[i] = displayName;
- }
- break;
- case SORT_ORDER_LAST_MODIFIED:
- mValueLong[i] = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
- break;
- case SORT_ORDER_SIZE:
- mValueLong[i] = getCursorLong(cursor, Document.COLUMN_SIZE);
- break;
- }
- }
-
- switch (sortOrder) {
- case SORT_ORDER_DISPLAY_NAME:
- synchronized (SortingCursorWrapper.class) {
-
- binarySort(mPosition, mValueString);
- }
- break;
- case SORT_ORDER_LAST_MODIFIED:
- case SORT_ORDER_SIZE:
- binarySort(mPosition, mValueLong);
- break;
- }
- }
-
- @Override
- public Bundle getExtras() {
- return mCursor.getExtras();
- }
-
- @Override
- public void close() {
- super.close();
- mCursor.close();
- }
-
- @Override
- public boolean onMove(int oldPosition, int newPosition) {
- return mCursor.moveToPosition(mPosition[newPosition]);
- }
-
- @Override
- public String[] getColumnNames() {
- return mCursor.getColumnNames();
- }
-
- @Override
- public int getCount() {
- return mCursor.getCount();
- }
-
- @Override
- public double getDouble(int column) {
- return mCursor.getDouble(column);
- }
-
- @Override
- public float getFloat(int column) {
- return mCursor.getFloat(column);
- }
-
- @Override
- public int getInt(int column) {
- return mCursor.getInt(column);
- }
-
- @Override
- public long getLong(int column) {
- return mCursor.getLong(column);
- }
-
- @Override
- public short getShort(int column) {
- return mCursor.getShort(column);
- }
-
- @Override
- public String getString(int column) {
- return mCursor.getString(column);
- }
-
- @Override
- public int getType(int column) {
- return mCursor.getType(column);
- }
-
- @Override
- public boolean isNull(int column) {
- return mCursor.isNull(column);
- }
-
- /**
- * Borrowed from TimSort.binarySort(), but modified to sort two column
- * dataset.
- */
- private static void binarySort(int[] position, String[] value) {
- final int count = position.length;
- for (int start = 1; start < count; start++) {
- final int pivotPosition = position[start];
- final String pivotValue = value[start];
-
- int left = 0;
- int right = start;
-
- while (left < right) {
- int mid = (left + right) >>> 1;
-
- final String lhs = pivotValue;
- final String rhs = value[mid];
- final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
-
- if (compare < 0) {
- right = mid;
- } else {
- left = mid + 1;
- }
- }
-
- int n = start - left;
- switch (n) {
- case 2:
- position[left + 2] = position[left + 1];
- value[left + 2] = value[left + 1];
- case 1:
- position[left + 1] = position[left];
- value[left + 1] = value[left];
- break;
- default:
- System.arraycopy(position, left, position, left + 1, n);
- System.arraycopy(value, left, value, left + 1, n);
- }
-
- position[left] = pivotPosition;
- value[left] = pivotValue;
- }
- }
-
- /**
- * Borrowed from TimSort.binarySort(), but modified to sort two column
- * dataset.
- */
- private static void binarySort(int[] position, long[] value) {
- final int count = position.length;
- for (int start = 1; start < count; start++) {
- final int pivotPosition = position[start];
- final long pivotValue = value[start];
-
- int left = 0;
- int right = start;
-
- while (left < right) {
- int mid = (left + right) >>> 1;
-
- final long lhs = pivotValue;
- final long rhs = value[mid];
- final int compare = Long.compare(lhs, rhs);
- if (compare > 0) {
- right = mid;
- } else {
- left = mid + 1;
- }
- }
-
- int n = start - left;
- switch (n) {
- case 2:
- position[left + 2] = position[left + 1];
- value[left + 2] = value[left + 1];
- case 1:
- position[left + 1] = position[left];
- value[left + 1] = value[left];
- break;
- default:
- System.arraycopy(position, left, position, left + 1, n);
- System.arraycopy(value, left, value, left + 1, n);
- }
-
- position[left] = pivotPosition;
- value[left] = pivotValue;
- }
- }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index c81d4fb..46372c0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -36,7 +36,7 @@
/** Explicit user choice */
public int userMode = MODE_UNKNOWN;
/** Derived after loader */
- public int derivedMode = MODE_LIST;
+ public int derivedMode = MODE_GRID;
/** Explicit user choice */
public int userSortOrder = SORT_ORDER_UNKNOWN;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 770d011..9617582 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -23,7 +23,6 @@
import static com.android.documentsui.State.MODE_UNKNOWN;
import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
-import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
@@ -36,30 +35,25 @@
import android.app.FragmentTransaction;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ClipData;
-import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Looper;
-import android.os.OperationCanceledException;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutManager;
@@ -67,17 +61,12 @@
import android.support.v7.widget.RecyclerView.RecyclerListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.text.format.Formatter;
-import android.text.format.Time;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseBooleanArray;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.DragEvent;
import android.view.GestureDetector;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -89,7 +78,6 @@
import android.widget.TextView;
import com.android.documentsui.BaseActivity;
-import com.android.documentsui.BaseActivity.DocumentContext;
import com.android.documentsui.CopyService;
import com.android.documentsui.DirectoryLoader;
import com.android.documentsui.DirectoryResult;
@@ -97,42 +85,32 @@
import com.android.documentsui.DocumentsActivity;
import com.android.documentsui.DocumentsApplication;
import com.android.documentsui.Events;
-import com.android.documentsui.IconUtils;
import com.android.documentsui.Menus;
import com.android.documentsui.MessageBar;
import com.android.documentsui.MimePredicate;
-import com.android.documentsui.ProviderExecutor;
-import com.android.documentsui.ProviderExecutor.Preemptable;
import com.android.documentsui.R;
import com.android.documentsui.RecentLoader;
import com.android.documentsui.RecentsProvider;
import com.android.documentsui.RecentsProvider.StateColumns;
-import com.android.documentsui.RootCursorWrapper;
import com.android.documentsui.RootsCache;
import com.android.documentsui.Shared;
-import com.android.documentsui.Shared;
import com.android.documentsui.Snackbars;
import com.android.documentsui.State;
-import com.android.documentsui.ThumbnailCache;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.RootInfo;
-import com.android.internal.annotations.GuardedBy;
import com.google.common.collect.Lists;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Display the documents inside a single directory.
*/
-public class DirectoryFragment extends Fragment {
-
- public static final String TAG = "DirectoryFragment";
+public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
public static final int TYPE_NORMAL = 1;
public static final int TYPE_SEARCH = 2;
@@ -145,8 +123,10 @@
public static final int REQUEST_COPY_DESTINATION = 1;
+ private static final String TAG = "DirectoryFragment";
+
private static final int LOADER_ID = 42;
- private static final boolean DEBUG_ENABLE_DND = true;
+ static final boolean DEBUG_ENABLE_DND = true;
private static final String EXTRA_TYPE = "type";
private static final String EXTRA_ROOT = "root";
@@ -159,6 +139,8 @@
private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
private ItemClickListener mItemClickListener = new ItemClickListener();
+ private IconHelper mIconHelper;
+
private View mEmptyView;
private RecyclerView mRecView;
@@ -168,9 +150,6 @@
private int mLastMode = MODE_UNKNOWN;
private int mLastSortOrder = SORT_ORDER_UNKNOWN;
private boolean mLastShowSize;
- private boolean mHideGridTitles;
- private boolean mSvelteRecents;
- private Point mThumbSize;
private DocumentsAdapter mAdapter;
private LoaderCallbacks<DirectoryResult> mCallbacks;
private FragmentTuner mTuner;
@@ -183,9 +162,6 @@
private MessageBar mMessageBar;
private View mProgressBar;
- private int mSelectedItemColor;
- private int mDefaultItemColor;
-
public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc, int anim) {
show(fm, TYPE_NORMAL, root, doc, null, anim);
}
@@ -313,11 +289,12 @@
final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
- mAdapter = new DocumentsAdapter(context);
- mRecView.setAdapter(mAdapter);
+ mIconHelper = new IconHelper(context, state.derivedMode);
- mDefaultItemColor = context.getResources().getColor(R.color.item_doc_background);
- mSelectedItemColor = context.getResources().getColor(R.color.item_doc_background_selected);
+ mAdapter = new SectionBreakDocumentsAdapterWrapper(
+ this, new ModelBackedDocumentsAdapter(this, mIconHelper));
+
+ mRecView.setAdapter(mAdapter);
GestureDetector.SimpleOnGestureListener listener =
new GestureDetector.SimpleOnGestureListener() {
@@ -355,12 +332,14 @@
// into the selection manager.
mSelectionManager = new MultiSelectManager(
mRecView,
+ mAdapter,
state.allowMultiple
? MultiSelectManager.MODE_MULTIPLE
: MultiSelectManager.MODE_SINGLE);
mSelectionManager.addCallback(new SelectionModeListener());
- mModel = new Model(context, mAdapter);
+ mModel = new Model(context);
+ mModel.addUpdateListener(mAdapter);
mModel.addUpdateListener(mModelUpdateListener);
mType = getArguments().getInt(EXTRA_TYPE);
@@ -369,17 +348,20 @@
mTuner = FragmentTuner.pick(state);
mClipper = new DocumentClipper(context);
+ boolean hideGridTitles;
if (mType == TYPE_RECENT_OPEN) {
// Hide titles when showing recents for picking images/videos
- mHideGridTitles = MimePredicate.mimeMatches(
+ hideGridTitles = MimePredicate.mimeMatches(
MimePredicate.VISUAL_MIMES, state.acceptMimes);
} else {
- mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+ hideGridTitles = (doc != null) && doc.isGridTitlesHidden();
}
+ GridDocumentHolder.setHideTitles(hideGridTitles);
final ActivityManager am = (ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE);
- mSvelteRecents = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+ boolean svelte = am.isLowRamDevice() && (mType == TYPE_RECENT_OPEN);
+ mIconHelper.setThumbnailsEnabled(!svelte);
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
@Override
@@ -439,6 +421,9 @@
if (container != null && !getArguments().getBoolean(EXTRA_IGNORE_STATE, false)) {
getView().restoreHierarchyState(container);
} else if (mLastSortOrder != state.derivedSortOrder) {
+ // The derived sort order takes the user sort order into account, but applies
+ // directory-specific defaults when the user doesn't explicitly set the sort
+ // order. Scroll to the top if the sort order actually changed.
mRecView.smoothScrollToPosition(0);
}
@@ -475,19 +460,14 @@
data.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_COPY));
}
- private int getEventAdapterPosition(MotionEvent e) {
- View view = mRecView.findChildViewUnder(e.getX(), e.getY());
- return view != null ? mRecView.getChildAdapterPosition(view) : RecyclerView.NO_POSITION;
- }
-
private boolean onSingleTapUp(MotionEvent e) {
// Only respond to touch events. Single-click mouse events are selection events and are
// handled by the selection manager. Tap events that occur while the selection manager is
// active are also selection events.
if (Events.isTouchEvent(e) && !mSelectionManager.hasSelection()) {
- int position = getEventAdapterPosition(e);
- if (position != RecyclerView.NO_POSITION) {
- return handleViewItem(position);
+ String id = getModelId(e);
+ if (id != null) {
+ return handleViewItem(id);
}
}
return false;
@@ -496,16 +476,16 @@
protected boolean onDoubleTap(MotionEvent e) {
if (Events.isMouseEvent(e)) {
Log.d(TAG, "Handling double tap from mouse.");
- int position = getEventAdapterPosition(e);
- if (position != RecyclerView.NO_POSITION) {
- return handleViewItem(position);
+ String id = getModelId(e);
+ if (id != null) {
+ return handleViewItem(id);
}
}
return false;
}
- private boolean handleViewItem(int position) {
- final Cursor cursor = mModel.getItem(position);
+ private boolean handleViewItem(String id) {
+ final Cursor cursor = mModel.getItem(id);
checkNotNull(cursor, "Cursor cannot be null.");
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -592,19 +572,19 @@
* classes as needed.
*/
private void updateLayout(int mode) {
- final int thumbSize;
-
final LayoutManager layout;
switch (mode) {
case MODE_GRID:
- thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
if (mGridLayout == null) {
- mGridLayout = new GridLayoutManager(getContext(), mColumnCount );
+ mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
+ SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+ if (lookup != null) {
+ mGridLayout.setSpanSizeLookup(lookup);
+ }
}
layout = mGridLayout;
break;
case MODE_LIST:
- thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
if (mListLayout == null) {
mListLayout = new LinearLayoutManager(getContext());
}
@@ -620,7 +600,7 @@
// imperatively calling this function.
mSelectionManager.handleLayoutChanged();
// setting layout manager automatically invalidates existing ViewHolders.
- mThumbSize = new Point(thumbSize, thumbSize);
+ mIconHelper.setMode(mode);
}
private int calculateColumnCount() {
@@ -635,6 +615,11 @@
return columnCount;
}
+ @Override
+ public int getColumnCount() {
+ return mColumnCount;
+ }
+
/**
* Manages the integration between our ActionMode and MultiSelectManager, initiating
* ActionMode when there is a selection, canceling it when there is no selection,
@@ -649,9 +634,9 @@
private Menu mMenu;
@Override
- public boolean onBeforeItemStateChange(int position, boolean selected) {
+ public boolean onBeforeItemStateChange(String modelId, boolean selected) {
if (selected) {
- final Cursor cursor = mModel.getItem(position);
+ final Cursor cursor = mModel.getItem(modelId);
checkNotNull(cursor, "Cursor cannot be null.");
final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -661,8 +646,8 @@
}
@Override
- public void onItemStateChanged(int position, boolean selected) {
- final Cursor cursor = mModel.getItem(position);
+ public void onItemStateChanged(String modelId, boolean selected) {
+ final Cursor cursor = mModel.getItem(modelId);
checkNotNull(cursor, "Cursor cannot be null.");
final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -781,14 +766,10 @@
}
}
- private static void cancelThumbnailTask(View view) {
+ private void cancelThumbnailTask(View view) {
final ImageView iconThumb = (ImageView) view.findViewById(R.id.icon_thumb);
if (iconThumb != null) {
- final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
- if (oldTask != null) {
- oldTask.preempt();
- iconThumb.setTag(null);
- }
+ mIconHelper.stopLoading(iconThumb);
}
}
@@ -854,8 +835,11 @@
Context context = getActivity();
String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
- mModel.markForDeletion(selected);
+ // Hide the files in the UI.
+ final SparseArray<String> toDelete = mAdapter.hide(selected.getAll());
+ // Show a snackbar informing the user that files will be deleted, and give them an option to
+ // cancel.
final Activity activity = getActivity();
Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
.setAction(
@@ -869,19 +853,22 @@
@Override
public void onDismissed(Snackbar snackbar, int event) {
if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
- mModel.undoDeletion();
+ // If the delete was cancelled, just unhide the files.
+ mAdapter.unhide(toDelete);
} else {
- mModel.finalizeDeletion(
+ // Actually kick off the delete.
+ mModel.delete(
+ selected,
new Model.DeletionListener() {
@Override
- public void onError() {
- Snackbars.makeSnackbar(
- activity,
- R.string.toast_failed_delete,
- Snackbar.LENGTH_LONG)
- .show();
+ public void onError() {
+ Snackbars.makeSnackbar(
+ activity,
+ R.string.toast_failed_delete,
+ Snackbar.LENGTH_LONG)
+ .show();
- }
+ }
});
}
}
@@ -917,61 +904,32 @@
}.execute(selected);
}
- private State getDisplayState() {
+ @Override
+ public void initDocumentHolder(DocumentHolder holder) {
+ holder.addClickListener(mItemClickListener);
+ holder.addOnKeyListener(mSelectionManager);
+ }
+
+ @Override
+ public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
+ if (DEBUG_ENABLE_DND) {
+ setupDragAndDropOnDocumentView(holder.itemView, cursor);
+ }
+ }
+
+ @Override
+ public State getDisplayState() {
return ((BaseActivity) getActivity()).getDisplayState();
}
- // Provide a reference to the views for each data item
- // Complex data items may need more than one view per item, and
- // you provide access to all the views for a data item in a view holder
- private final class DocumentHolder
- extends RecyclerView.ViewHolder
- implements View.OnKeyListener
- {
- public String docId; // The stable document id.
- private ClickListener mClickListener;
- private View.OnKeyListener mKeyListener;
-
- public DocumentHolder(View view) {
- super(view);
- view.setOnKeyListener(this);
- }
-
- public void setSelected(boolean selected) {
- itemView.setActivated(selected);
- itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
- }
-
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // Intercept enter key-up events, and treat them as clicks. Forward other events.
- if (event.getAction() == KeyEvent.ACTION_UP &&
- keyCode == KeyEvent.KEYCODE_ENTER) {
- if (mClickListener != null) {
- mClickListener.onClick(this);
- }
- return true;
- } else if (mKeyListener != null) {
- return mKeyListener.onKey(v, keyCode, event);
- }
- return false;
- }
-
- public void addClickListener(ClickListener listener) {
- // Just handle one for now; switch to a list if necessary.
- checkState(mClickListener == null);
- mClickListener = listener;
- }
-
- public void addOnKeyListener(View.OnKeyListener listener) {
- // Just handle one for now; switch to a list if necessary.
- checkState(mKeyListener == null);
- mKeyListener = listener;
- }
+ @Override
+ public Model getModel() {
+ return mModel;
}
- interface ClickListener {
- public void onClick(DocumentHolder doc);
+ @Override
+ public boolean isDocumentEnabled(String docMimeType, int docFlags) {
+ return mTuner.isDocumentEnabled(docMimeType, docFlags);
}
void showEmptyView() {
@@ -997,250 +955,6 @@
mRecView.setVisibility(View.VISIBLE);
}
- private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
-
- private final Context mContext;
- private final LayoutInflater mInflater;
-
- public DocumentsAdapter(Context context) {
- mContext = context;
- mInflater = LayoutInflater.from(context);
- }
-
- @Override
- public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- final State state = getDisplayState();
- final LayoutInflater inflater = LayoutInflater.from(getContext());
- View item = null;
- switch (state.derivedMode) {
- case MODE_GRID:
- item = inflater.inflate(R.layout.item_doc_grid, parent, false);
- break;
- case MODE_LIST:
- item = inflater.inflate(R.layout.item_doc_list, parent, false);
- break;
- case MODE_UNKNOWN:
- default:
- throw new IllegalStateException("Unsupported layout mode.");
- }
-
- DocumentHolder holder = new DocumentHolder(item);
- holder.addClickListener(mItemClickListener);
- holder.addOnKeyListener(mSelectionManager);
- return holder;
- }
-
- /**
- * Deal with selection changed events by using a custom ItemAnimator that just changes the
- * background color. This works around focus issues (otherwise items lose focus when their
- * selection state changes) but also optimizes change animations for selection.
- */
- @Override
- public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
- final View itemView = holder.itemView;
-
- if (payload.contains(MultiSelectManager.SELECTION_CHANGED_MARKER)) {
- final boolean selected = isSelected(position);
- itemView.setActivated(selected);
- return;
- } else {
- onBindViewHolder(holder, position);
- }
- }
-
- @Override
- public void onBindViewHolder(DocumentHolder holder, int position) {
-
- final Context context = getContext();
- final State state = getDisplayState();
- final RootsCache roots = DocumentsApplication.getRootsCache(context);
- final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
- context, mThumbSize);
-
- final Cursor cursor = mModel.getItem(position);
- checkNotNull(cursor, "Cursor cannot be null.");
-
- final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
- final String docRootId = getCursorString(cursor, RootCursorWrapper.COLUMN_ROOT_ID);
- final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
- final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
- final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
- final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
- final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
- final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
-
- holder.docId = docId;
- final View itemView = holder.itemView;
-
- holder.setSelected(isSelected(position));
-
- final ImageView iconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
- final ImageView iconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
- final TextView title = (TextView) itemView.findViewById(android.R.id.title);
- final ImageView icon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
- final TextView summary = (TextView) itemView.findViewById(android.R.id.summary);
- final TextView date = (TextView) itemView.findViewById(R.id.date);
- final TextView size = (TextView) itemView.findViewById(R.id.size);
-
- final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) iconThumb.getTag();
- if (oldTask != null) {
- oldTask.preempt();
- iconThumb.setTag(null);
- }
-
- iconMime.animate().cancel();
- iconThumb.animate().cancel();
-
- final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
- final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
- || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
- final boolean showThumbnail = supportsThumbnail && allowThumbnail && !mSvelteRecents;
-
- final boolean enabled = mTuner.isDocumentEnabled(docMimeType, docFlags);
- final float iconAlpha = (state.derivedMode == MODE_LIST && !enabled) ? 0.5f : 1f;
-
- boolean cacheHit = false;
- if (showThumbnail) {
- final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
- final Bitmap cachedResult = thumbs.get(uri);
- if (cachedResult != null) {
- iconThumb.setImageBitmap(cachedResult);
- cacheHit = true;
- } else {
- iconThumb.setImageDrawable(null);
- // TODO: Hang this off DocumentHolder?
- final ThumbnailAsyncTask task = new ThumbnailAsyncTask(
- uri, iconMime, iconThumb, mThumbSize, iconAlpha);
- iconThumb.setTag(task);
- ProviderExecutor.forAuthority(docAuthority).execute(task);
- }
- }
-
- // Always throw MIME icon into place, even when a thumbnail is being
- // loaded in background.
- if (cacheHit) {
- iconMime.setAlpha(0f);
- iconMime.setImageDrawable(null);
- iconThumb.setAlpha(1f);
- } else {
- iconMime.setAlpha(1f);
- iconThumb.setAlpha(0f);
- iconThumb.setImageDrawable(null);
- iconMime.setImageDrawable(
- getDocumentIcon(mContext, docAuthority, docId, docMimeType, docIcon, state));
- }
-
- if ((state.derivedMode == MODE_GRID) && mHideGridTitles) {
- title.setVisibility(View.GONE);
- } else {
- title.setText(docDisplayName);
- title.setVisibility(View.VISIBLE);
- }
-
- Drawable iconDrawable = null;
- if (mType == TYPE_RECENT_OPEN) {
- // We've already had to enumerate roots before any results can
- // be shown, so this will never block.
- final RootInfo root = roots.getRootBlocking(docAuthority, docRootId);
- iconDrawable = root.loadIcon(mContext);
-
- if (summary != null) {
- final boolean alwaysShowSummary = getResources()
- .getBoolean(R.bool.always_show_summary);
- if (alwaysShowSummary) {
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
- } else {
- if (iconDrawable != null && roots.isIconUniqueBlocking(root)) {
- // No summary needed if icon speaks for itself
- summary.setVisibility(View.INVISIBLE);
- } else {
- summary.setText(root.getDirectoryString());
- summary.setVisibility(View.VISIBLE);
- summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
- }
- }
- }
- } else {
- // Directories showing thumbnails in grid mode get a little icon
- // hint to remind user they're a directory.
- if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
- && showThumbnail) {
- iconDrawable = IconUtils.applyTintAttr(mContext, R.drawable.ic_doc_folder,
- android.R.attr.textColorPrimaryInverse);
- }
-
- if (summary != null) {
- if (docSummary != null) {
- summary.setText(docSummary);
- summary.setVisibility(View.VISIBLE);
- } else {
- summary.setVisibility(View.INVISIBLE);
- }
- }
- }
-
- if (iconDrawable != null) {
- icon1.setVisibility(View.VISIBLE);
- icon1.setImageDrawable(iconDrawable);
- } else {
- icon1.setVisibility(View.GONE);
- }
-
- if (docLastModified == -1) {
- date.setText(null);
- } else {
- date.setText(formatTime(mContext, docLastModified));
- }
-
- if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
- size.setVisibility(View.GONE);
- } else {
- size.setVisibility(View.VISIBLE);
- size.setText(Formatter.formatFileSize(mContext, docSize));
- }
-
- setEnabledRecursive(itemView, enabled);
-
- iconMime.setAlpha(iconAlpha);
- iconThumb.setAlpha(iconAlpha);
- icon1.setAlpha(iconAlpha);
-
- if (DEBUG_ENABLE_DND) {
- setupDragAndDropOnDocumentView(itemView, cursor);
- }
- }
-
- @Override
- public int getItemCount() {
- return mModel.getItemCount();
- }
-
- }
-
- private static String formatTime(Context context, long when) {
- // TODO: DateUtils should make this easier
- Time then = new Time();
- then.set(when);
- Time now = new Time();
- now.setToNow();
-
- int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT
- | DateUtils.FORMAT_ABBREV_ALL;
-
- if (then.year != now.year) {
- flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE;
- } else if (then.yearDay != now.yearDay) {
- flags |= DateUtils.FORMAT_SHOW_DATE;
- } else {
- flags |= DateUtils.FORMAT_SHOW_TIME;
- }
-
- return DateUtils.formatDateTime(context, when, flags);
- }
-
private String findCommonMimeType(List<String> mimeTypes) {
String[] commonType = mimeTypes.get(0).split("/");
if (commonType.length != 2) {
@@ -1265,19 +979,6 @@
return commonType[0] + "/" + commonType[1];
}
- private void setEnabledRecursive(View v, boolean enabled) {
- if (v == null) return;
- if (v.isEnabled() == enabled) return;
- v.setEnabled(enabled);
-
- if (v instanceof ViewGroup) {
- final ViewGroup vg = (ViewGroup) v;
- for (int i = vg.getChildCount() - 1; i >= 0; i--) {
- setEnabledRecursive(vg.getChildAt(i), enabled);
- }
- }
- }
-
private void copyFromClipboard() {
new AsyncTask<Void, Void, List<DocumentInfo>>() {
@@ -1373,7 +1074,7 @@
Snackbars.makeSnackbar(activity,
activity.getResources().getQuantityString(
R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
- Snackbar.LENGTH_SHORT).show();
+ Snackbar.LENGTH_SHORT).show();
}
}.execute(selection);
}
@@ -1409,7 +1110,8 @@
}
public void selectAllFiles() {
- boolean changed = mSelectionManager.setItemsSelected(0, mModel.getItemCount(), true);
+ // Only select things currently visible in the adapter.
+ boolean changed = mSelectionManager.setItemsSelected(mAdapter.getModelIds(), true);
if (changed) {
updateDisplayState();
}
@@ -1452,10 +1154,10 @@
return true;
case DragEvent.ACTION_DROP:
- int dstPosition = mRecView.getChildAdapterPosition(getContainingItemView(v));
+ String dstId = getModelId(v);
DocumentInfo dstDir = null;
- if (dstPosition != android.widget.AdapterView.INVALID_POSITION) {
- Cursor dstCursor = mModel.getItem(dstPosition);
+ if (dstId != null) {
+ Cursor dstCursor = mModel.getItem(dstId);
checkNotNull(dstCursor, "Cursor cannot be null.");
dstDir = DocumentInfo.fromDirectoryCursor(dstCursor);
// TODO: Do not drop into the directory where the documents came from.
@@ -1467,10 +1169,37 @@
}
};
- private View getContainingItemView(View view) {
+ /**
+ * Gets the model ID for a given motion event (using the event position)
+ */
+ private String getModelId(MotionEvent e) {
+ View view = mRecView.findChildViewUnder(e.getX(), e.getY());
+ if (view == null) {
+ return null;
+ }
+ RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+ if (vh instanceof DocumentHolder) {
+ return ((DocumentHolder) vh).modelId;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the model ID for a given RecyclerView item.
+ * @param view A View that is a document item view, or a child of a document item view.
+ * @return The Model ID for the given document, or null if the given view is not associated with
+ * a document item view.
+ */
+ private String getModelId(View view) {
while (true) {
if (view.getLayoutParams() instanceof RecyclerView.LayoutParams) {
- return view;
+ RecyclerView.ViewHolder vh = mRecView.getChildViewHolder(view);
+ if (vh instanceof DocumentHolder) {
+ return ((DocumentHolder) vh).modelId;
+ } else {
+ return null;
+ }
}
ViewParent parent = view.getParent();
if (parent == null || !(parent instanceof View)) {
@@ -1499,22 +1228,22 @@
};
private List<DocumentInfo> getDraggableDocuments(View currentItemView) {
- int position = mRecView.getChildAdapterPosition(getContainingItemView(currentItemView));
- if (position == android.widget.AdapterView.INVALID_POSITION) {
+ String modelId = getModelId(currentItemView);
+ if (modelId == null) {
return Collections.EMPTY_LIST;
}
final List<DocumentInfo> selectedDocs =
mModel.getDocuments(mSelectionManager.getSelection());
if (!selectedDocs.isEmpty()) {
- if (!isSelected(position)) {
+ if (!isSelected(modelId)) {
// There is a selection that does not include the current item, drag nothing.
return Collections.EMPTY_LIST;
}
return selectedDocs;
}
- final Cursor cursor = mModel.getItem(position);
+ final Cursor cursor = mModel.getItem(modelId);
checkNotNull(cursor, "Cursor cannot be null.");
final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
@@ -1524,89 +1253,12 @@
private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
if (docs.size() == 1) {
final DocumentInfo doc = docs.get(0);
- return getDocumentIcon(getActivity(), doc.authority, doc.documentId,
- doc.mimeType, doc.icon, getDisplayState());
+ return mIconHelper.getDocumentIcon(getActivity(), doc.authority, doc.documentId,
+ doc.mimeType, doc.icon);
}
return getActivity().getDrawable(R.drawable.ic_doc_generic);
}
- public static Drawable getDocumentIcon(Context context, String docAuthority, String docId,
- String docMimeType, int docIcon, State state) {
- if (docIcon != 0) {
- return IconUtils.loadPackageIcon(context, docAuthority, docIcon);
- } else {
- return IconUtils.loadMimeIcon(context, docMimeType, docAuthority, docId,
- state.derivedMode);
- }
- }
-
- private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap>
- implements Preemptable {
- private final Uri mUri;
- private final ImageView mIconMime;
- private final ImageView mIconThumb;
- private final Point mThumbSize;
- private final float mTargetAlpha;
- private final CancellationSignal mSignal;
-
- public ThumbnailAsyncTask(Uri uri, ImageView iconMime, ImageView iconThumb, Point thumbSize,
- float targetAlpha) {
- mUri = uri;
- mIconMime = iconMime;
- mIconThumb = iconThumb;
- mThumbSize = thumbSize;
- mTargetAlpha = targetAlpha;
- mSignal = new CancellationSignal();
- }
-
- @Override
- public void preempt() {
- cancel(false);
- mSignal.cancel();
- }
-
- @Override
- protected Bitmap doInBackground(Uri... params) {
- if (isCancelled()) return null;
-
- final Context context = mIconThumb.getContext();
- final ContentResolver resolver = context.getContentResolver();
-
- ContentProviderClient client = null;
- Bitmap result = null;
- try {
- client = DocumentsApplication.acquireUnstableProviderOrThrow(
- resolver, mUri.getAuthority());
- result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
- if (result != null) {
- final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
- context, mThumbSize);
- thumbs.put(mUri, result);
- }
- } catch (Exception e) {
- if (!(e instanceof OperationCanceledException)) {
- Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
- }
- } finally {
- ContentProviderClient.releaseQuietly(client);
- }
- return result;
- }
-
- @Override
- protected void onPostExecute(Bitmap result) {
- if (mIconThumb.getTag() == this && result != null) {
- mIconThumb.setTag(null);
- mIconThumb.setImageBitmap(result);
-
- mIconMime.setAlpha(mTargetAlpha);
- mIconMime.animate().alpha(0f).start();
- mIconThumb.setAlpha(0f);
- mIconThumb.animate().alpha(mTargetAlpha).start();
- }
- }
- }
-
private class DrawableShadowBuilder extends View.DragShadowBuilder {
private final Drawable mShadow;
@@ -1653,322 +1305,24 @@
abstract void onDocumentsReady(List<DocumentInfo> docs);
}
- boolean isSelected(int position) {
- return mSelectionManager.getSelection().contains(position);
+ @Override
+ public boolean isSelected(String modelId) {
+ return mSelectionManager.getSelection().contains(modelId);
}
- /**
- * The data model for the current loaded directory.
- */
- @VisibleForTesting
- public static final class Model implements DocumentContext {
- private RecyclerView.Adapter<?> mViewAdapter;
- private Context mContext;
- private int mCursorCount;
- private boolean mIsLoading;
- @GuardedBy("mPendingDelete")
- private Boolean mPendingDelete = false;
- @GuardedBy("mPendingDelete")
- private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
- private UpdateListener mUpdateListener;
- @Nullable private Cursor mCursor;
- @Nullable private String info;
- @Nullable private String error;
-
- Model(Context context, RecyclerView.Adapter<?> viewAdapter) {
- mContext = context;
- mViewAdapter = viewAdapter;
- }
-
- void update(DirectoryResult result) {
- if (DEBUG) Log.i(TAG, "Updating model with new result set.");
-
- if (result == null) {
- mCursor = null;
- mCursorCount = 0;
- info = null;
- error = null;
- mIsLoading = false;
- mUpdateListener.onModelUpdate(this);
- return;
- }
-
- if (result.exception != null) {
- Log.e(TAG, "Error while loading directory contents", result.exception);
- mUpdateListener.onModelUpdateFailed(result.exception);
- return;
- }
-
- mCursor = result.cursor;
- mCursorCount = mCursor.getCount();
-
- final Bundle extras = mCursor.getExtras();
- if (extras != null) {
- info = extras.getString(DocumentsContract.EXTRA_INFO);
- error = extras.getString(DocumentsContract.EXTRA_ERROR);
- mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
- }
-
- mUpdateListener.onModelUpdate(this);
- }
-
- int getItemCount() {
- synchronized(mPendingDelete) {
- return mCursorCount - mMarkedForDeletion.size();
- }
- }
-
- Cursor getItem(int position) {
- synchronized(mPendingDelete) {
- // Items marked for deletion are masked out of the UI. To do this, for every marked
- // item whose position is less than the requested item position, advance the requested
- // position by 1.
- final int originalPos = position;
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- // It'd be more concise, but less efficient, to iterate over positions while calling
- // mMarkedForDeletion.get. Instead, iterate over deleted entries.
- if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
- ++position;
- }
- }
-
- if (DEBUG && position != originalPos) {
- Log.d(TAG, "Item position adjusted for deletion. Original: " + originalPos
- + " Adjusted: " + position);
- }
-
- if (position >= mCursorCount) {
- throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
- mCursorCount + " items");
- }
-
- mCursor.moveToPosition(position);
- return mCursor;
- }
- }
-
- private boolean isEmpty() {
- return mCursorCount == 0;
- }
-
- private boolean isLoading() {
- return mIsLoading;
- }
-
- List<DocumentInfo> getDocuments(Selection items) {
- final int size = (items != null) ? items.size() : 0;
-
- final List<DocumentInfo> docs = new ArrayList<>(size);
- for (int i = 0; i < size; i++) {
- final Cursor cursor = getItem(items.get(i));
- checkNotNull(cursor, "Cursor cannot be null.");
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
- docs.add(doc);
- }
- return docs;
- }
-
- @Override
- public Cursor getCursor() {
- if (Looper.myLooper() != Looper.getMainLooper()) {
- throw new IllegalStateException("Can't call getCursor from non-main thread.");
- }
- return mCursor;
- }
-
- List<DocumentInfo> getDocumentsMarkedForDeletion() {
- synchronized (mPendingDelete) {
- final int size = mMarkedForDeletion.size();
- List<DocumentInfo> docs = new ArrayList<>(size);
-
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- checkState(position < mCursorCount);
- mCursor.moveToPosition(position);
- final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
- docs.add(doc);
- }
- return docs;
- }
- }
-
- /**
- * Marks the given files for deletion. This will remove them from the UI. Clients must then
- * call either {@link #undoDeletion()} or {@link #finalizeDeletion()} to cancel or confirm
- * the deletion, respectively. Only one deletion operation is allowed at a time.
- *
- * @param selected A selection representing the files to delete.
- */
- void markForDeletion(Selection selected) {
- synchronized (mPendingDelete) {
- mPendingDelete = true;
- // Only one deletion operation at a time.
- checkState(mMarkedForDeletion.size() == 0);
- // There should never be more to delete than what exists.
- checkState(mCursorCount >= selected.size());
-
- int[] positions = selected.getAll();
- Arrays.sort(positions);
-
- // Walk backwards through the set, since we're removing positions.
- // Otherwise, positions would change after the first modification.
- for (int p = positions.length - 1; p >= 0; p--) {
- mMarkedForDeletion.append(positions[p], true);
- mViewAdapter.notifyItemRemoved(positions[p]);
- if (DEBUG) Log.d(TAG, "Scheduled " + positions[p] + " for delete.");
- }
- }
- }
-
- /**
- * Cancels an ongoing deletion operation. All files currently marked for deletion will be
- * unmarked, and restored in the UI. See {@link #markForDeletion(Selection)}.
- */
- void undoDeletion() {
- synchronized (mPendingDelete) {
- // Iterate over deleted items, temporarily marking them false in the deletion list, and
- // re-adding them to the UI.
- final int size = mMarkedForDeletion.size();
- for (int i = 0; i < size; ++i) {
- final int position = mMarkedForDeletion.keyAt(i);
- mMarkedForDeletion.put(position, false);
- mViewAdapter.notifyItemInserted(position);
- }
- resetDeleteData();
- }
- }
-
- private void resetDeleteData() {
- synchronized (mPendingDelete) {
- mPendingDelete = false;
- mMarkedForDeletion.clear();
- }
- }
-
- /**
- * Finalizes an ongoing deletion operation. All files currently marked for deletion will be
- * deleted. See {@link #markForDeletion(Selection)}.
- *
- * @param view The view which will be used to interact with the user (e.g. surfacing
- * snackbars) for errors, info, etc.
- */
- void finalizeDeletion(DeletionListener listener) {
- synchronized (mPendingDelete) {
- if (mPendingDelete) {
- // Necessary to avoid b/25072545. Even when that's resolved, this
- // is a nice safe thing to day.
- mPendingDelete = false;
- final ContentResolver resolver = mContext.getContentResolver();
- DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
- task.execute();
- }
- }
- }
-
- /**
- * A Task which collects the DocumentInfo for documents that have been marked for deletion,
- * and actually deletes them.
- */
- private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
- private ContentResolver mResolver;
- private DeletionListener mListener;
-
- /**
- * @param resolver A ContentResolver for performing the actual file deletions.
- * @param errorCallback A Runnable that is executed in the event that one or more errors
- * occured while copying files. Execution will occur on the UI thread.
- */
- public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) {
- mResolver = resolver;
- mListener = listener;
- }
-
- @Override
- protected List<DocumentInfo> doInBackground(Void... params) {
- return getDocumentsMarkedForDeletion();
- }
-
- @Override
- protected void onPostExecute(List<DocumentInfo> docs) {
- boolean hadTrouble = false;
- for (DocumentInfo doc : docs) {
- if (!doc.isDeleteSupported()) {
- Log.w(TAG, doc + " could not be deleted. Skipping...");
- hadTrouble = true;
- continue;
- }
-
- ContentProviderClient client = null;
- try {
- if (DEBUG) Log.d(TAG, "Deleting: " + doc.displayName);
- client = DocumentsApplication.acquireUnstableProviderOrThrow(
- mResolver, doc.derivedUri.getAuthority());
- DocumentsContract.deleteDocument(client, doc.derivedUri);
- } catch (Exception e) {
- Log.w(TAG, "Failed to delete " + doc);
- hadTrouble = true;
- } finally {
- ContentProviderClient.releaseQuietly(client);
- }
- }
-
- if (hadTrouble) {
- // TODO show which files failed? b/23720103
- mListener.onError();
- if (DEBUG) Log.d(TAG, "Deletion task completed. Some deletions failed.");
- } else {
- if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
- }
- resetDeleteData();
-
- mListener.onCompletion();
- }
- }
-
- static class DeletionListener {
- /**
- * Called when deletion has completed (regardless of whether an error occurred).
- */
- void onCompletion() {}
-
- /**
- * Called at the end of a deletion operation that produced one or more errors.
- */
- void onError() {}
- }
-
- void addUpdateListener(UpdateListener listener) {
- checkState(mUpdateListener == null);
- mUpdateListener = listener;
- }
-
- static class UpdateListener {
- /**
- * Called when a successful update has occurred.
- */
- void onModelUpdate(Model model) {}
-
- /**
- * Called when an update has been attempted but failed.
- */
- void onModelUpdateFailed(Exception e) {}
- }
- }
-
- private class ItemClickListener implements ClickListener {
+ private class ItemClickListener implements DocumentHolder.ClickListener {
@Override
public void onClick(DocumentHolder doc) {
- final int position = doc.getAdapterPosition();
if (mSelectionManager.hasSelection()) {
- mSelectionManager.toggleSelection(position);
+ mSelectionManager.toggleSelection(doc.modelId);
+ mSelectionManager.setSelectionRangeBegin(doc.getAdapterPosition());
} else {
- handleViewItem(position);
+ handleViewItem(doc.modelId);
}
}
}
- private class ModelUpdateListener extends Model.UpdateListener {
+ private final class ModelUpdateListener implements Model.UpdateListener {
@Override
public void onModelUpdate(Model model) {
if (model.info != null || model.error != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
new file mode 100644
index 0000000..9ac9057
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+public abstract class DocumentHolder
+ extends RecyclerView.ViewHolder
+ implements View.OnKeyListener {
+
+ public @Nullable String modelId;
+
+ final int mSelectedItemColor;
+ final int mDefaultItemColor;
+ final boolean mAlwaysShowSummary;
+ final Context mContext;
+
+ private ListDocumentHolder.ClickListener mClickListener;
+ private View.OnKeyListener mKeyListener;
+
+ public DocumentHolder(Context context, ViewGroup parent, int layout) {
+ this(context, inflateLayout(context, parent, layout));
+ }
+
+ public DocumentHolder(Context context, View item) {
+ super(item);
+
+ itemView.setOnKeyListener(this);
+
+ mContext = context;
+
+ mDefaultItemColor = context.getColor(R.color.item_doc_background);
+ mSelectedItemColor = context.getColor(R.color.item_doc_background_selected);
+ mAlwaysShowSummary = context.getResources().getBoolean(R.bool.always_show_summary);
+ }
+
+ /**
+ * Binds the view to the given item data.
+ * @param cursor
+ * @param modelId
+ * @param state
+ */
+ public abstract void bind(Cursor cursor, String modelId, State state);
+
+ public void setSelected(boolean selected) {
+ itemView.setActivated(selected);
+ itemView.setBackgroundColor(selected ? mSelectedItemColor : mDefaultItemColor);
+ }
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ // Intercept enter key-up events, and treat them as clicks. Forward other events.
+ if (event.getAction() == KeyEvent.ACTION_UP &&
+ keyCode == KeyEvent.KEYCODE_ENTER) {
+ if (mClickListener != null) {
+ mClickListener.onClick(this);
+ }
+ return true;
+ } else if (mKeyListener != null) {
+ return mKeyListener.onKey(v, keyCode, event);
+ }
+ return false;
+ }
+
+ public void addClickListener(ListDocumentHolder.ClickListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mClickListener == null);
+ mClickListener = listener;
+ }
+
+ public void addOnKeyListener(View.OnKeyListener listener) {
+ // Just handle one for now; switch to a list if necessary.
+ checkState(mKeyListener == null);
+ mKeyListener = listener;
+ }
+
+ public void setEnabled(boolean enabled) {
+ setEnabledRecursive(itemView, enabled);
+ }
+
+ static void setEnabledRecursive(View itemView, boolean enabled) {
+ if (itemView == null) return;
+ if (itemView.isEnabled() == enabled) return;
+ itemView.setEnabled(enabled);
+
+ if (itemView instanceof ViewGroup) {
+ final ViewGroup vg = (ViewGroup) itemView;
+ for (int i = vg.getChildCount() - 1; i >= 0; i--) {
+ setEnabledRecursive(vg.getChildAt(i), enabled);
+ }
+ }
+ }
+
+ private static View inflateLayout(Context context, ViewGroup parent, int layout) {
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ return inflater.inflate(layout, parent, false);
+ }
+
+ interface ClickListener {
+ public void onClick(DocumentHolder doc);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
new file mode 100644
index 0000000..43c2f63
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+
+import com.android.documentsui.State;
+
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.util.List;
+
+/**
+ * DocumentsAdapter provides glue between a directory Model, and RecylcerView. We've
+ * abstracted this a bit in order to decompose some specialized support
+ * for adding dummy layout objects (@see SectionBreakDocumentsAdapter). Handling of the
+ * dummy layout objects was error prone when interspersed with the core mode / adapter code.
+ *
+ * @see ModelBackedDocumentsAdapter
+ * @see SectionBreakDocumentsAdapter
+ */
+abstract class DocumentsAdapter
+ extends RecyclerView.Adapter<DocumentHolder>
+ implements Model.UpdateListener {
+
+ // Payloads for notifyItemChange to distinguish between selection and other events.
+ static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
+ /**
+ * Returns a list of model IDs of items currently in the adapter. Excludes items that are
+ * currently hidden (see {@link #hide(String...)}).
+ *
+ * @return A list of Model IDs.
+ */
+ abstract List<String> getModelIds();
+
+ /**
+ * Triggers item-change notifications by stable ID (as opposed to position).
+ * Passing an unrecognized ID will result in a warning in logcat, but no other error.
+ */
+ abstract void onItemSelectionChanged(String id);
+
+ /**
+ * @return The model ID of the item at the given adapter position.
+ */
+ abstract String getModelId(int position);
+
+ /**
+ * Hides a set of items from the associated RecyclerView.
+ *
+ * @param ids The Model IDs of the items to hide.
+ * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
+ * to {@link #unhide} the items if necessary.
+ */
+ abstract public SparseArray<String> hide(String... ids);
+
+ /**
+ * Unhides a set of previously hidden items.
+ *
+ * @param ids A sparse array of IDs from a previous call to {@link #hide}.
+ */
+ abstract void unhide(SparseArray<String> ids);
+
+ /**
+ * Returns a class that yields the span size for a particular element. This is
+ * primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
+ * we adjust sizes.
+ */
+ GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+ throw new UnsupportedAddressTypeException();
+ }
+
+ static boolean isDirectory(Cursor cursor) {
+ final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ return Document.MIME_TYPE_DIR.equals(mimeType);
+ }
+
+ boolean isDirectory(Model model, int position) {
+ String modelId = getModelIds().get(position);
+ Cursor cursor = model.getItem(modelId);
+ return isDirectory(cursor);
+ }
+
+ /**
+ * Environmental access for View adapter implementations.
+ */
+ interface Environment {
+ Context getContext();
+ int getColumnCount();
+ State getDisplayState();
+ boolean isSelected(String id);
+ Model getModel();
+ boolean isDocumentEnabled(String mimeType, int flags);
+ void initDocumentHolder(DocumentHolder holder);
+ void onBindDocumentHolder(DocumentHolder holder, Cursor cursor);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
new file mode 100644
index 0000000..ab67a5b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.widget.Space;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+final class EmptyDocumentHolder extends DocumentHolder {
+ public EmptyDocumentHolder(Context context) {
+ super(context, new Space(context));
+
+ // Per UX spec, this puts a bigger gap between the folders and documents in the grid.
+ final int gridMargin = context.getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
+ itemView.setMinimumHeight(gridMargin * 2);
+ }
+
+ public void bind(Cursor cursor, String modelId, State state) {
+ // Nothing to bind.
+ return;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
new file mode 100644
index 0000000..11ff263
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+final class GridDirectoryHolder extends DocumentHolder {
+ final TextView mTitle;
+ public GridDirectoryHolder(Context context, ViewGroup parent) {
+ super(context, parent, R.layout.item_dir_grid);
+
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ public void bind(Cursor cursor, String modelId, State state) {
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ this.modelId = modelId;
+
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ mTitle.setText(docDisplayName);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
new file mode 100644
index 0000000..5f34ac3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class GridDocumentHolder extends DocumentHolder {
+ private static boolean mHideTitles;
+
+ final TextView mTitle;
+ final TextView mDate;
+ final TextView mSize;
+ final ImageView mIconMimeLg;
+ final ImageView mIconMimeSm;
+ final ImageView mIconThumb;
+ final IconHelper mIconHelper;
+
+
+ public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+ super(context, parent, R.layout.item_doc_grid);
+
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ mDate = (TextView) itemView.findViewById(R.id.date);
+ mSize = (TextView) itemView.findViewById(R.id.size);
+ mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime);
+ mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+ mIconMimeSm = (ImageView) itemView.findViewById(android.R.id.icon1);
+ mIconHelper = iconHelper;
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ public void bind(Cursor cursor, String modelId, State state) {
+ this.modelId = modelId;
+
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+ final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+ final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+ mIconHelper.stopLoading(mIconThumb);
+
+ mIconMimeLg.animate().cancel();
+ mIconMimeLg.setAlpha(1f);
+ mIconThumb.animate().cancel();
+ mIconThumb.setAlpha(0f);
+
+ mIconMimeSm.setImageDrawable(IconUtils.loadMimeIcon(mContext, docMimeType));
+
+ final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg);
+
+ if (mHideTitles) {
+ mTitle.setVisibility(View.GONE);
+ } else {
+ mTitle.setText(docDisplayName);
+ mTitle.setVisibility(View.VISIBLE);
+ }
+
+ if (docLastModified == -1) {
+ mDate.setText(null);
+ } else {
+ mDate.setText(Shared.formatTime(mContext, docLastModified));
+ }
+
+ if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
+ mSize.setVisibility(View.GONE);
+ } else {
+ mSize.setVisibility(View.VISIBLE);
+ mSize.setText(Formatter.formatFileSize(mContext, docSize));
+ }
+ }
+
+ /**
+ * Sets whether to hide titles on subsequently created GridDocumentHolder items.
+ * @param hideTitles
+ */
+ public static void setHideTitles(boolean hideTitles) {
+ mHideTitles = hideTitles;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
new file mode 100644
index 0000000..ff70eaf
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Point;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.widget.ImageView;
+
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.IconUtils;
+import com.android.documentsui.MimePredicate;
+import com.android.documentsui.ProviderExecutor;
+import com.android.documentsui.ProviderExecutor.Preemptable;
+import com.android.documentsui.R;
+import com.android.documentsui.ThumbnailCache;
+
+/**
+ * A class to assist with loading and managing the Images (i.e. thumbnails and icons) associated
+ * with items in the directory listing.
+ */
+public class IconHelper {
+ private static String TAG = "IconHelper";
+
+ private Context mContext;
+ private ThumbnailCache mCache;
+ private Point mThumbSize;
+ // The display mode (MODE_GRID, MODE_LIST, etc).
+ private int mMode;
+ private boolean mThumbnailsEnabled = true;
+
+ /**
+ * @param context
+ * @param mode MODE_GRID or MODE_LIST
+ */
+ public IconHelper(Context context, int mode) {
+ mContext = context;
+ setMode(mode);
+ mCache = DocumentsApplication.getThumbnailsCache(context, mThumbSize);
+ }
+
+ /**
+ * Enables or disables thumbnails. When thumbnails are disabled, mime icons (or custom icons, if
+ * specified by the document) are used instead.
+ *
+ * @param enabled
+ */
+ public void setThumbnailsEnabled(boolean enabled) {
+ mThumbnailsEnabled = enabled;
+ }
+
+ /**
+ * Sets the current display mode. This affects the thumbnail sizes that are loaded.
+ * @param mode See {@link State.MODE_LIST} and {@link State.MODE_GRID}.
+ */
+ public void setMode(int mode) {
+ // TODO: Instead of exposing setMode, make the mode final, and make separate instances for
+ // grid/list.
+ int thumbSize;
+ switch (mode) {
+ case MODE_GRID:
+ thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.grid_width);
+ break;
+ case MODE_LIST:
+ thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.icon_size);
+ break;
+ case MODE_UNKNOWN:
+ default:
+ throw new IllegalArgumentException("Unsupported layout mode: " + mode);
+ }
+ mMode = mode;
+ mThumbSize = new Point(thumbSize, thumbSize);
+ }
+
+ /**
+ * Cancels any ongoing load operations associated with the given ImageView.
+ * @param icon
+ */
+ public void stopLoading(ImageView icon) {
+ final LoaderTask oldTask = (LoaderTask) icon.getTag();
+ if (oldTask != null) {
+ oldTask.preempt();
+ icon.setTag(null);
+ }
+ }
+
+ /** Internal task for loading thumbnails asynchronously. */
+ private static class LoaderTask
+ extends AsyncTask<Uri, Void, Bitmap>
+ implements Preemptable {
+ private final Uri mUri;
+ private final ImageView mIconMime;
+ private final ImageView mIconThumb;
+ private final Point mThumbSize;
+ private final CancellationSignal mSignal;
+
+ public LoaderTask(Uri uri, ImageView iconMime, ImageView iconThumb,
+ Point thumbSize) {
+ mUri = uri;
+ mIconMime = iconMime;
+ mIconThumb = iconThumb;
+ mThumbSize = thumbSize;
+ mSignal = new CancellationSignal();
+ if (DEBUG) Log.d(TAG, "Starting icon loader task for " + mUri);
+ }
+
+ @Override
+ public void preempt() {
+ if (DEBUG) Log.d(TAG, "Icon loader task for " + mUri + " was cancelled.");
+ cancel(false);
+ mSignal.cancel();
+ }
+
+ @Override
+ protected Bitmap doInBackground(Uri... params) {
+ if (isCancelled())
+ return null;
+
+ final Context context = mIconThumb.getContext();
+ final ContentResolver resolver = context.getContentResolver();
+
+ ContentProviderClient client = null;
+ Bitmap result = null;
+ try {
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ resolver, mUri.getAuthority());
+ result = DocumentsContract.getDocumentThumbnail(client, mUri, mThumbSize, mSignal);
+ if (result != null) {
+ final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
+ context, mThumbSize);
+ thumbs.put(mUri, result);
+ }
+ } catch (Exception e) {
+ if (!(e instanceof OperationCanceledException)) {
+ Log.w(TAG, "Failed to load thumbnail for " + mUri + ": " + e);
+ }
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap result) {
+ if (DEBUG) Log.d(TAG, "Loader task for " + mUri + " completed");
+
+ if (mIconThumb.getTag() == this && result != null) {
+ mIconThumb.setTag(null);
+ mIconThumb.setImageBitmap(result);
+
+ float alpha = mIconMime.getAlpha();
+ mIconMime.animate().alpha(0f).start();
+ mIconThumb.setAlpha(0f);
+ mIconThumb.animate().alpha(alpha).start();
+ }
+ }
+ }
+
+ /**
+ * Load thumbnails for a directory list item.
+ * @param uri The URI for the file being represented.
+ * @param mimeType The mime type of the file being represented.
+ * @param docFlags Flags for the file being represented.
+ * @param docIcon Custom icon (if any) for the file being requested.
+ * @param iconThumb The itemview's thumbnail icon.
+ * @param iconMime The itemview's mime icon.
+ * @return
+ */
+ public void loadThumbnail(Uri uri, String mimeType, int docFlags, int docIcon,
+ ImageView iconThumb, ImageView iconMime) {
+ boolean cacheHit = false;
+
+ final String docAuthority = uri.getAuthority();
+
+ final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
+ final boolean allowThumbnail = (mMode == MODE_GRID)
+ || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mimeType);
+ final boolean showThumbnail = supportsThumbnail && allowThumbnail && mThumbnailsEnabled;
+ if (showThumbnail) {
+ final Bitmap cachedResult = mCache.get(uri);
+ if (cachedResult != null) {
+ iconThumb.setImageBitmap(cachedResult);
+ cacheHit = true;
+ } else {
+ iconThumb.setImageDrawable(null);
+ final LoaderTask task = new LoaderTask(uri, iconMime, iconThumb, mThumbSize);
+ iconThumb.setTag(task);
+ ProviderExecutor.forAuthority(docAuthority).execute(task);
+ }
+ }
+
+ if (cacheHit) {
+ iconMime.setImageDrawable(null);
+ iconMime.setAlpha(0f);
+ iconThumb.setAlpha(1f);
+ } else {
+ // Add a mime icon if the thumbnail is being loaded in the background.
+ iconThumb.setImageDrawable(null);
+ iconMime.setImageDrawable(getDocumentIcon(
+ mContext, docAuthority, DocumentsContract.getDocumentId(uri), mimeType, docIcon));
+ iconMime.setAlpha(1f);
+ iconThumb.setAlpha(0f);
+ }
+ }
+
+ /**
+ * Gets a mime icon or package icon for a file.
+ * @param context
+ * @param authority The authority string of the file.
+ * @param id The document ID of the file.
+ * @param mimeType The mime type of the file.
+ * @param icon The custom icon (if any) of the file.
+ * @return
+ */
+ public Drawable getDocumentIcon(Context context, String authority, String id,
+ String mimeType, int icon) {
+ if (icon != 0) {
+ return IconUtils.loadPackageIcon(context, authority, icon);
+ } else {
+ return IconUtils.loadMimeIcon(context, mimeType, authority, id, mMode);
+ }
+ }
+
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
new file mode 100644
index 0000000..c22e91d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.documentsui.R;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.Shared;
+import com.android.documentsui.State;
+
+final class ListDocumentHolder extends DocumentHolder {
+ final TextView mTitle;
+ final TextView mSummary;
+ final TextView mDate;
+ final TextView mSize;
+ final ImageView mIconMime;
+ final ImageView mIconThumb;
+ final ImageView mIcon1;
+ final IconHelper mIconHelper;
+
+ public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) {
+ super(context, parent, R.layout.item_doc_list);
+
+ mTitle = (TextView) itemView.findViewById(android.R.id.title);
+ mSummary = (TextView) itemView.findViewById(android.R.id.summary);
+ mDate = (TextView) itemView.findViewById(R.id.date);
+ mSize = (TextView) itemView.findViewById(R.id.size);
+ mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
+ mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
+ mIcon1 = (ImageView) itemView.findViewById(android.R.id.icon1);
+
+ mIconHelper = iconHelper;
+ }
+
+ /**
+ * Bind this view to the given document for display.
+ * @param cursor Pointing to the item to be bound.
+ * @param modelId The model ID of the item.
+ * @param state Current display state.
+ */
+ @Override
+ public void bind(Cursor cursor, String modelId, State state) {
+ this.modelId = modelId;
+
+ checkNotNull(cursor, "Cursor cannot be null.");
+
+ final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+ final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final String docDisplayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ final long docLastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
+ final int docIcon = getCursorInt(cursor, Document.COLUMN_ICON);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+ final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
+ final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+
+ mIconHelper.stopLoading(mIconThumb);
+
+ mIconMime.animate().cancel();
+ mIconThumb.animate().cancel();
+
+ final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
+ mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime);
+
+ mTitle.setText(docDisplayName);
+ mTitle.setVisibility(View.VISIBLE);
+
+ if (docSummary != null) {
+ mSummary.setText(docSummary);
+ mSummary.setVisibility(View.VISIBLE);
+ } else {
+ mSummary.setVisibility(View.INVISIBLE);
+ }
+
+ if (docLastModified == -1) {
+ mDate.setText(null);
+ } else {
+ mDate.setText(Shared.formatTime(mContext, docLastModified));
+ }
+
+ if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
+ mSize.setVisibility(View.GONE);
+ } else {
+ mSize.setVisibility(View.VISIBLE);
+ mSize.setText(Formatter.formatFileSize(mContext, docSize));
+ }
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+ final float iconAlpha = enabled ? 1f : 0.5f;
+ mIconMime.setAlpha(iconAlpha);
+ mIconThumb.setAlpha(iconAlpha);
+ mIcon1.setAlpha(iconAlpha);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
new file mode 100644
index 0000000..f2bade5
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Looper;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.android.documentsui.BaseActivity.SiblingProvider;
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.DocumentsApplication;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The data model for the current loaded directory.
+ */
+@VisibleForTesting
+public class Model implements SiblingProvider {
+ private static final String TAG = "Model";
+
+ private Context mContext;
+ private boolean mIsLoading;
+ private List<UpdateListener> mUpdateListeners = new ArrayList<>();
+ @Nullable private Cursor mCursor;
+ private int mCursorCount;
+ /** Maps Model ID to cursor positions, for looking up items by Model ID. */
+ private Map<String, Integer> mPositions = new HashMap<>();
+ /**
+ * A sorted array of model IDs for the files currently in the Model. Sort order is determined
+ * by {@link #mSortOrder}
+ */
+ private List<String> mIds = new ArrayList<>();
+ private int mSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+ @Nullable String info;
+ @Nullable String error;
+
+ Model(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+ * string that can be used to identify the document referred to by the cursor.
+ *
+ * @param c A cursor that refers to a document.
+ */
+ private static String createModelId(Cursor c) {
+ // TODO: Maybe more efficient to use just the document ID, in cases where there is only one
+ // authority (which should be the majority of cases).
+ return createModelId(
+ getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY),
+ getCursorString(c, Document.COLUMN_DOCUMENT_ID));
+ }
+
+ /**
+ * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+ * string that can be used to identify the document referred to by the cursor.
+ *
+ * @param c A cursor that refers to a document.
+ */
+ static String createModelId(String authority, String docId) {
+ return authority + "|" + docId;
+ }
+
+ private void notifyUpdateListeners() {
+ for (UpdateListener listener: mUpdateListeners) {
+ listener.onModelUpdate(this);
+ }
+ }
+
+ private void notifyUpdateListeners(Exception e) {
+ for (UpdateListener listener: mUpdateListeners) {
+ listener.onModelUpdateFailed(e);
+ }
+ }
+
+ void update(DirectoryResult result) {
+ if (DEBUG) Log.i(TAG, "Updating model with new result set.");
+
+ if (result == null) {
+ mCursor = null;
+ mCursorCount = 0;
+ mIds.clear();
+ mPositions.clear();
+ info = null;
+ error = null;
+ mIsLoading = false;
+ notifyUpdateListeners();
+ return;
+ }
+
+ if (result.exception != null) {
+ Log.e(TAG, "Error while loading directory contents", result.exception);
+ notifyUpdateListeners(result.exception);
+ return;
+ }
+
+ mCursor = result.cursor;
+ mCursorCount = mCursor.getCount();
+ mSortOrder = result.sortOrder;
+
+ updateModelData();
+
+ final Bundle extras = mCursor.getExtras();
+ if (extras != null) {
+ info = extras.getString(DocumentsContract.EXTRA_INFO);
+ error = extras.getString(DocumentsContract.EXTRA_ERROR);
+ mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
+ }
+
+ notifyUpdateListeners();
+ }
+
+ @VisibleForTesting
+ int getItemCount() {
+ return mCursorCount;
+ }
+
+ /**
+ * Scan over the incoming cursor data, generate Model IDs for each row, and sort the IDs
+ * according to the current sort order.
+ */
+ private void updateModelData() {
+ int[] positions = new int[mCursorCount];
+ mIds.clear();
+ String[] stringValues = new String[mCursorCount];
+ long[] longValues = null;
+
+ if (mSortOrder == SORT_ORDER_LAST_MODIFIED || mSortOrder == SORT_ORDER_SIZE) {
+ longValues = new long[mCursorCount];
+ }
+
+ mCursor.moveToPosition(-1);
+ for (int pos = 0; pos < mCursorCount; ++pos) {
+ mCursor.moveToNext();
+ positions[pos] = pos;
+ mIds.add(createModelId(mCursor));
+
+ switch(mSortOrder) {
+ case SORT_ORDER_DISPLAY_NAME:
+ final String mimeType = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+ final String displayName = getCursorString(
+ mCursor, Document.COLUMN_DISPLAY_NAME);
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ stringValues[pos] = DocumentInfo.DIR_PREFIX + displayName;
+ } else {
+ stringValues[pos] = displayName;
+ }
+ break;
+ case SORT_ORDER_LAST_MODIFIED:
+ longValues[pos] = getCursorLong(mCursor, Document.COLUMN_LAST_MODIFIED);
+ stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+ break;
+ case SORT_ORDER_SIZE:
+ longValues[pos] = getCursorLong(mCursor, Document.COLUMN_SIZE);
+ stringValues[pos] = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
+ break;
+ }
+ }
+
+ switch (mSortOrder) {
+ case SORT_ORDER_DISPLAY_NAME:
+ binarySort(stringValues, positions, mIds);
+ break;
+ case SORT_ORDER_LAST_MODIFIED:
+ case SORT_ORDER_SIZE:
+ binarySort(longValues, stringValues, positions, mIds);
+ break;
+ }
+
+ // Populate the positions.
+ mPositions.clear();
+ for (int i = 0; i < mCursorCount; ++i) {
+ mPositions.put(mIds.get(i), positions[i]);
+ }
+ }
+
+ /**
+ * Sorts model data. Takes three columns of index-corresponded data. The first column is the
+ * sort key. Rows are sorted in ascending alphabetical order on the sort key. This code is based
+ * on TimSort.binarySort().
+ *
+ * @param sortKey Data is sorted in ascending alphabetical order.
+ * @param positions Cursor positions to be sorted.
+ * @param ids Model IDs to be sorted.
+ */
+ private static void binarySort(String[] sortKey, int[] positions, List<String> ids) {
+ final int count = positions.length;
+ for (int start = 1; start < count; start++) {
+ final int pivotPosition = positions[start];
+ final String pivotValue = sortKey[start];
+ final String pivotId = ids.get(start);
+
+ int left = 0;
+ int right = start;
+
+ while (left < right) {
+ int mid = (left + right) >>> 1;
+
+ final String lhs = pivotValue;
+ final String rhs = sortKey[mid];
+ final int compare = DocumentInfo.compareToIgnoreCaseNullable(lhs, rhs);
+
+ if (compare < 0) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+
+ int n = start - left;
+ switch (n) {
+ case 2:
+ positions[left + 2] = positions[left + 1];
+ sortKey[left + 2] = sortKey[left + 1];
+ ids.set(left + 2, ids.get(left + 1));
+ case 1:
+ positions[left + 1] = positions[left];
+ sortKey[left + 1] = sortKey[left];
+ ids.set(left + 1, ids.get(left));
+ break;
+ default:
+ System.arraycopy(positions, left, positions, left + 1, n);
+ System.arraycopy(sortKey, left, sortKey, left + 1, n);
+ for (int i = n; i >= 1; --i) {
+ ids.set(left + i, ids.get(left + i - 1));
+ }
+ }
+
+ positions[left] = pivotPosition;
+ sortKey[left] = pivotValue;
+ ids.set(left, pivotId);
+ }
+ }
+
+ /**
+ * Sorts model data. Takes four columns of index-corresponded data. The first column is the sort
+ * key, and the second is an array of mime types. The rows are first bucketed by mime type
+ * (directories vs documents) and then each bucket is sorted independently in descending
+ * numerical order on the sort key. This code is based on TimSort.binarySort().
+ *
+ * @param sortKey Data is sorted in descending numerical order.
+ * @param mimeTypes Corresponding mime types. Directories will be sorted ahead of documents.
+ * @param positions Cursor positions to be sorted.
+ * @param ids Model IDs to be sorted.
+ */
+ private static void binarySort(
+ long[] sortKey, String[] mimeTypes, int[] positions, List<String> ids) {
+ final int count = positions.length;
+ for (int start = 1; start < count; start++) {
+ final int pivotPosition = positions[start];
+ final long pivotValue = sortKey[start];
+ final String pivotMime = mimeTypes[start];
+ final String pivotId = ids.get(start);
+
+ int left = 0;
+ int right = start;
+
+ while (left < right) {
+ int mid = ((left + right) >>> 1);
+
+ // First bucket by mime type. Directories always go in front.
+ int compare = 0;
+ final boolean lhsIsDir = Document.MIME_TYPE_DIR.equals(pivotMime);
+ final boolean rhsIsDir = Document.MIME_TYPE_DIR.equals(mimeTypes[mid]);
+ if (lhsIsDir && !rhsIsDir) {
+ compare = -1;
+ } else if (!lhsIsDir && rhsIsDir) {
+ compare = 1;
+ } else {
+ final long lhs = pivotValue;
+ final long rhs = sortKey[mid];
+ // Sort in descending numerical order. This matches legacy behaviour, which yields
+ // largest or most recent items on top.
+ compare = -Long.compare(lhs, rhs);
+ }
+
+ if (compare < 0) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+
+ int n = start - left;
+ switch (n) {
+ case 2:
+ positions[left + 2] = positions[left + 1];
+ sortKey[left + 2] = sortKey[left + 1];
+ mimeTypes[left + 2] = mimeTypes[left + 1];
+ ids.set(left + 2, ids.get(left + 1));
+ case 1:
+ positions[left + 1] = positions[left];
+ sortKey[left + 1] = sortKey[left];
+ mimeTypes[left + 1] = mimeTypes[left];
+ ids.set(left + 1, ids.get(left));
+ break;
+ default:
+ System.arraycopy(positions, left, positions, left + 1, n);
+ System.arraycopy(sortKey, left, sortKey, left + 1, n);
+ System.arraycopy(mimeTypes, left, mimeTypes, left + 1, n);
+ for (int i = n; i >= 1; --i) {
+ ids.set(left + i, ids.get(left + i - 1));
+ }
+ }
+
+ positions[left] = pivotPosition;
+ sortKey[left] = pivotValue;
+ mimeTypes[left] = pivotMime;
+ ids.set(left, pivotId);
+ }
+ }
+
+ @Nullable Cursor getItem(String modelId) {
+ Integer pos = mPositions.get(modelId);
+ if (pos != null) {
+ mCursor.moveToPosition(pos);
+ return mCursor;
+ }
+ return null;
+ }
+
+ boolean isEmpty() {
+ return mCursorCount == 0;
+ }
+
+ boolean isLoading() {
+ return mIsLoading;
+ }
+
+ List<DocumentInfo> getDocuments(Selection items) {
+ final int size = (items != null) ? items.size() : 0;
+
+ final List<DocumentInfo> docs = new ArrayList<>(size);
+ for (String modelId: items.getAll()) {
+ final Cursor cursor = getItem(modelId);
+ checkNotNull(cursor, "Cursor cannot be null.");
+ final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+ docs.add(doc);
+ }
+ return docs;
+ }
+
+ @Override
+ public Cursor getCursor() {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ throw new IllegalStateException("Can't call getCursor from non-main thread.");
+ }
+ return mCursor;
+ }
+
+ public void delete(Selection selected, DeletionListener listener) {
+ final ContentResolver resolver = mContext.getContentResolver();
+ new DeleteFilesTask(resolver, listener).execute(selected);
+ }
+
+ /**
+ * A Task which collects the DocumentInfo for documents that have been marked for deletion,
+ * and actually deletes them.
+ */
+ private class DeleteFilesTask extends AsyncTask<Selection, Void, Void> {
+ private ContentResolver mResolver;
+ private DeletionListener mListener;
+ private boolean mHadTrouble;
+
+ /**
+ * @param resolver A ContentResolver for performing the actual file deletions.
+ * @param errorCallback A Runnable that is executed in the event that one or more errors
+ * occurred while copying files. Execution will occur on the UI thread.
+ */
+ public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) {
+ mResolver = resolver;
+ mListener = listener;
+ }
+
+ @Override
+ protected Void doInBackground(Selection... selected) {
+ List<DocumentInfo> toDelete = null;
+ try {
+ toDelete = getDocuments(selected[0]);
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Failed to retrieve documents for delete.");
+ mHadTrouble = true;
+ return null;
+ }
+
+ for (DocumentInfo doc : toDelete) {
+ if (!doc.isDeleteSupported()) {
+ Log.w(TAG, doc + " could not be deleted. Skipping...");
+ mHadTrouble = true;
+ continue;
+ }
+
+ ContentProviderClient client = null;
+ try {
+ if (DEBUG) Log.d(TAG, "Deleting: " + doc.displayName);
+ client = DocumentsApplication.acquireUnstableProviderOrThrow(
+ mResolver, doc.derivedUri.getAuthority());
+ DocumentsContract.deleteDocument(client, doc.derivedUri);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to delete " + doc, e);
+ mHadTrouble = true;
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void _) {
+ if (mHadTrouble) {
+ // TODO show which files failed? b/23720103
+ mListener.onError();
+ if (DEBUG) Log.d(TAG, "Deletion task completed. Some deletions failed.");
+ } else {
+ if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
+ }
+
+ mListener.onCompletion();
+ }
+ }
+
+ static class DeletionListener {
+ /**
+ * Called when deletion has completed (regardless of whether an error occurred).
+ */
+ void onCompletion() {}
+
+ /**
+ * Called at the end of a deletion operation that produced one or more errors.
+ */
+ void onError() {}
+ }
+
+ void addUpdateListener(UpdateListener listener) {
+ mUpdateListeners.add(listener);
+ }
+
+ static interface UpdateListener {
+ /**
+ * Called when a successful update has occurred.
+ */
+ void onModelUpdate(Model model);
+
+ /**
+ * Called when an update has been attempted but failed.
+ */
+ void onModelUpdateFailed(Exception e);
+ }
+
+ /**
+ * @return An ordered array of model IDs representing the documents in the model. It is sorted
+ * according to the current sort order, which was set by the last model update.
+ */
+ public List<String> getModelIds() {
+ return mIds;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
new file mode 100644
index 0000000..68756a3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Adapts from dirlist.Model to something RecyclerView understands.
+ */
+final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
+
+ private static final String TAG = "ModelBackedDocumentsAdapter";
+ public static final int ITEM_TYPE_DOCUMENT = 1;
+ public static final int ITEM_TYPE_DIRECTORY = 2;
+
+ // Provides access to information needed when creating and view holders. This
+ // isn't an ideal pattern (more transitive dependency stuff) but good enough for now.
+ private final Environment mEnv;
+ private final IconHelper mIconHelper; // a transitive dependency of the holders.
+
+ /**
+ * An ordered list of model IDs. This is the data structure that determines what shows up in
+ * the UI, and where.
+ */
+ private List<String> mModelIds = new ArrayList<>();
+
+ // List of files that have been deleted. Some transient directory updates
+ // may happen while files are being deleted. During this time we don't
+ // want once-hidden files to be re-shown. We only remove
+ // items from this list when we get a model update where the model
+ // does not contain a corresponding id. This ensures hidden entries
+ // don't momentarily re-appear if we get intermediate updates from
+ // the file system.
+ private Set<String> mHiddenIds = new HashSet<>();
+
+ public ModelBackedDocumentsAdapter(Environment env, IconHelper iconHelper) {
+ mEnv = env;
+ mIconHelper = iconHelper;
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ DocumentHolder holder = null;
+ final State state = mEnv.getDisplayState();
+ switch (state.derivedMode) {
+ case MODE_GRID:
+ switch (viewType) {
+ case ITEM_TYPE_DIRECTORY:
+ holder = new GridDirectoryHolder(mEnv.getContext(), parent);
+ break;
+ case ITEM_TYPE_DOCUMENT:
+ holder = new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+ break;
+ default:
+ throw new IllegalStateException("Unsupported layout type.");
+ }
+ break;
+ case MODE_LIST:
+ holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+ break;
+ case MODE_UNKNOWN:
+ default:
+ throw new IllegalStateException("Unsupported layout mode.");
+ }
+
+ mEnv.initDocumentHolder(holder);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
+ if (payload.contains(SELECTION_CHANGED_MARKER)) {
+ final boolean selected = mEnv.isSelected(mModelIds.get(position));
+ holder.setSelected(selected);
+ } else {
+ onBindViewHolder(holder, position);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position) {
+ String modelId = mModelIds.get(position);
+ Cursor cursor = mEnv.getModel().getItem(modelId);
+ holder.bind(cursor, modelId, mEnv.getDisplayState());
+
+ final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+
+ holder.setSelected(mEnv.isSelected(modelId));
+ holder.setEnabled(mEnv.isDocumentEnabled(docMimeType, docFlags));
+
+ mEnv.onBindDocumentHolder(holder, cursor);
+ }
+
+ @Override
+ public int getItemCount() {
+ return mModelIds.size();
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ if (DEBUG && mHiddenIds.size() > 0) {
+ Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
+ }
+
+ List<String> modelIds = model.getModelIds();
+ mModelIds = new ArrayList<>(modelIds.size());
+ for (String id : modelIds) {
+ if (!mHiddenIds.contains(id)) {
+ mModelIds.add(id);
+ } else {
+ if (DEBUG) Log.d(TAG, "Omitting hidden id from model during update: " + id);
+ }
+ }
+
+ // Finally remove any hidden ids that aren't present in the model.
+ // This assumes that model updates represent a complete set of files.
+ mHiddenIds.retainAll(mModelIds);
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ Log.w(TAG, "Model update failed.", e);
+ mModelIds.clear();
+ }
+
+ @Override
+ public String getModelId(int adapterPosition) {
+ return mModelIds.get(adapterPosition);
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ if (DEBUG) Log.d(TAG, "Hiding ids: " + ids);
+ Set<String> toHide = Sets.newHashSet(ids);
+
+ // Proceed backwards through the list of items, because each removal causes the
+ // positions of all subsequent items to change.
+ SparseArray<String> hiddenItems = new SparseArray<>();
+ for (int i = mModelIds.size() - 1; i >= 0; --i) {
+ String id = mModelIds.get(i);
+ if (toHide.contains(id)) {
+ mHiddenIds.add(id);
+ hiddenItems.put(i, mModelIds.remove(i));
+ notifyItemRemoved(i);
+ }
+ }
+
+ return hiddenItems;
+ }
+
+ @Override
+ public void unhide(SparseArray<String> ids) {
+ if (DEBUG) Log.d(TAG, "Un-iding ids: " + ids);
+
+ // An ArrayList can shrink at runtime...and in fact
+ // it does when we clear it completely.
+ // This means we can't call add(pos, id) without
+ // first checking the list size.
+ List<String> oldIds = mModelIds;
+ mModelIds = new ArrayList<>(oldIds.size() + ids.size());
+ mModelIds.addAll(oldIds);
+
+ // Finally insert the unhidden items.
+ for (int i = 0; i < ids.size(); i++) {
+ int pos = ids.keyAt(i);
+ String id = ids.get(pos);
+ mHiddenIds.remove(id);
+ mModelIds.add(pos, id);
+ notifyItemInserted(pos);
+ }
+ }
+
+ @Override
+ public List<String> getModelIds() {
+ return mModelIds;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return isDirectory(mEnv.getModel(), position)
+ ? ITEM_TYPE_DIRECTORY
+ : ITEM_TYPE_DOCUMENT;
+ }
+
+ @Override
+ public void onItemSelectionChanged(String id) {
+ int position = mModelIds.indexOf(id);
+
+ if (position >= 0) {
+ notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+ } else {
+ Log.w(TAG, "Item change notification received for unknown item: " + id);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index 65e1a28..5f317ff 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -28,10 +28,6 @@
import android.support.annotation.VisibleForTesting;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
-import android.support.v7.widget.RecyclerView.LayoutManager;
-import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -46,8 +42,14 @@
import com.android.documentsui.R;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* MultiSelectManager provides support traditional multi-item selection support to RecyclerView.
@@ -66,28 +68,23 @@
private final Selection mSelection = new Selection();
- // Only created when selection is cleared.
- private Selection mIntermediateSelection;
-
- private Range mRanger;
- private SelectionEnvironment mEnvironment;
-
+ private final SelectionEnvironment mEnvironment;
+ private final DocumentsAdapter mAdapter;
private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
- private Adapter<?> mAdapter;
+ private Range mRanger;
private boolean mSingleSelect;
- // Payloads for notifyItemChange to distinguish between selection and other events.
- public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
@Nullable private BandController mBandManager;
+
/**
* @param recyclerView
* @param mode Selection mode
*/
- public MultiSelectManager(final RecyclerView recyclerView, int mode) {
- this(recyclerView.getAdapter(), new RuntimeSelectionEnvironment(recyclerView), mode);
+ public MultiSelectManager(
+ final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
+ this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
if (mode == MODE_MULTIPLE) {
mBandManager = new BandController();
@@ -138,33 +135,42 @@
* @hide
*/
@VisibleForTesting
- MultiSelectManager(Adapter<?> adapter, SelectionEnvironment environment, int mode) {
- mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
+ MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
+ mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
mSingleSelect = mode == MODE_SINGLE;
mAdapter.registerAdapterDataObserver(
- new AdapterDataObserver() {
+ new RecyclerView.AdapterDataObserver() {
+
+ private List<String> mModelIds;
@Override
public void onChanged() {
+ // TODO: This is causing b/22765812
mSelection.clear();
+ mModelIds = mAdapter.getModelIds();
}
@Override
public void onItemRangeChanged(
- int positionStart, int itemCount, Object payload) {
+ int startPosition, int itemCount, Object payload) {
// No change in position. Ignoring.
}
@Override
- public void onItemRangeInserted(int positionStart, int itemCount) {
- mSelection.expand(positionStart, itemCount);
+ public void onItemRangeInserted(int startPosition, int itemCount) {
+ mSelection.cancelProvisionalSelection();
}
@Override
- public void onItemRangeRemoved(int positionStart, int itemCount) {
- mSelection.collapse(positionStart, itemCount);
+ public void onItemRangeRemoved(int startPosition, int itemCount) {
+ checkState(startPosition >= 0);
+ checkState(itemCount > 0);
+
+ mSelection.cancelProvisionalSelection();
+ // Remove any disappeared IDs from the selection.
+ mSelection.intersect(mModelIds);
}
@Override
@@ -214,36 +220,22 @@
}
/**
- * Causes item at {@code position} in adapter to be selected.
- *
- * @param position Adapter position
- * @param selected
- * @return True if the selection state of the item changed.
- */
- @VisibleForTesting
- public boolean setItemSelected(int position, boolean selected) {
- if (mSingleSelect && hasSelection()) {
- clearSelectionQuietly();
- }
- return setItemsSelected(position, 1, selected);
- }
-
- /**
* Sets the selected state of the specified items. Note that the callback will NOT
* be consulted to see if an item can be selected.
*
- * @return True if the selection state of any of the items changed.
+ * @param ids
+ * @param selected
+ * @return
*/
- public boolean setItemsSelected(int position, int length, boolean selected) {
+ public boolean setItemsSelected(Iterable<String> ids, boolean selected) {
boolean changed = false;
- for (int i = position; i < position + length; i++) {
- boolean itemChanged = selected ? mSelection.add(i) : mSelection.remove(i);
+ for (String id: ids) {
+ boolean itemChanged = selected ? mSelection.add(id) : mSelection.remove(id);
if (itemChanged) {
- notifyItemStateChanged(i, selected);
+ notifyItemStateChanged(id, selected);
}
changed |= itemChanged;
}
-
notifySelectionChanged();
return changed;
}
@@ -271,15 +263,12 @@
if (!hasSelection()) {
return;
}
- if (mIntermediateSelection == null) {
- mIntermediateSelection = new Selection();
- }
- getSelection(mIntermediateSelection);
+
+ Selection intermediateSelection = getSelection(new Selection());
mSelection.clear();
- for (int i = 0; i < mIntermediateSelection.size(); i++) {
- int position = mIntermediateSelection.get(i);
- notifyItemStateChanged(position, false);
+ for (String id: intermediateSelection.getAll()) {
+ notifyItemStateChanged(id, false);
}
}
@@ -301,7 +290,9 @@
// if this is a mouse click on an item, start selection mode.
// TODO: && input.isPrimaryButtonPressed(), but it is returning false.
if (input.isOverItem() && input.isMouseEvent()) {
- toggleSelection(input.getItemPosition());
+ int position = input.getItemPosition();
+ toggleSelection(position);
+ setSelectionRangeBegin(position);
}
return false;
}
@@ -330,29 +321,42 @@
// information about what has changed.
notifySelectionChanged();
} else {
- toggleSelection(input.getItemPosition());
+ int position = input.getItemPosition();
+ toggleSelection(position);
+ setSelectionRangeBegin(position);
}
}
/**
- * Toggles the selection state at position. If an item does end up selected
- * a new Ranger (range selection manager) at that point is created.
+ * A convenience method for toggling selection by adapter position.
*
- * @param position
+ * @param position Adapter position to toggle.
*/
- public void toggleSelection(int position) {
+ private void toggleSelection(int position) {
// Position may be special "no position" during certain
// transitional phases. If so, skip handling of the event.
if (position == RecyclerView.NO_POSITION) {
if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
return;
}
+ String id = mAdapter.getModelId(position);
+ if (id != null) {
+ toggleSelection(id);
+ }
+ }
+ /**
+ * Toggles selection on the item with the given model ID.
+ *
+ * @param modelId
+ */
+ public void toggleSelection(String modelId) {
+ checkNotNull(modelId);
boolean changed = false;
- if (mSelection.contains(position)) {
- changed = attemptDeselect(position);
+ if (mSelection.contains(modelId)) {
+ changed = attemptDeselect(modelId);
} else {
- boolean canSelect = notifyBeforeItemStateChange(position, true);
+ boolean canSelect = notifyBeforeItemStateChange(modelId, true);
if (!canSelect) {
return;
}
@@ -365,8 +369,7 @@
// an item to be selected.
// By recreating Ranger at this point, we allow the user to create
// multiple separate contiguous ranges with SHIFT+Click & Click.
- selectAndNotify(position);
- setSelectionFocusBegin(position);
+ selectAndNotify(modelId);
changed = true;
}
@@ -383,57 +386,68 @@
* @throws IllegalStateException if {@code position} is not already be selected
* @param position
*/
- void setSelectionFocusBegin(int position) {
- checkState(mSelection.contains(position));
- mRanger = new Range(position);
+ void setSelectionRangeBegin(int position) {
+ if (position == RecyclerView.NO_POSITION) {
+ return;
+ }
+
+ if (mSelection.contains(mAdapter.getModelId(position))) {
+ mRanger = new Range(position);
+ }
}
/**
- * Try to select all elements in range. Not that callbacks can cancel selection
- * of specific items, so some or even all items may not reflect the desired
- * state after the update is complete.
+ * Try to set selection state for all elements in range. Not that callbacks can cancel selection
+ * of specific items, so some or even all items may not reflect the desired state after the
+ * update is complete.
*
- * @param begin inclusive
- * @param end inclusive
- * @param selected
+ * @param begin Adapter position for range start (inclusive).
+ * @param end Adapter position for range end (inclusive).
+ * @param selected New selection state.
*/
private void updateRange(int begin, int end, boolean selected) {
checkState(end >= begin);
for (int i = begin; i <= end; i++) {
+ String id = mAdapter.getModelId(i);
+ if (id == null) {
+ continue;
+ }
+
if (selected) {
- boolean canSelect = notifyBeforeItemStateChange(i, true);
+ boolean canSelect = notifyBeforeItemStateChange(id, true);
if (canSelect) {
if (mSingleSelect && hasSelection()) {
clearSelectionQuietly();
}
- selectAndNotify(i);
+ selectAndNotify(id);
}
} else {
- attemptDeselect(i);
+ attemptDeselect(id);
}
}
}
/**
- * @param position
+ * @param modelId
* @return True if the update was applied.
*/
- private boolean selectAndNotify(int position) {
- boolean changed = mSelection.add(position);
+ private boolean selectAndNotify(String modelId) {
+ boolean changed = mSelection.add(modelId);
if (changed) {
- notifyItemStateChanged(position, true);
+ notifyItemStateChanged(modelId, true);
}
return changed;
}
/**
- * @param position
+ * @param id
* @return True if the update was applied.
*/
- private boolean attemptDeselect(int position) {
- if (notifyBeforeItemStateChange(position, false)) {
- mSelection.remove(position);
- notifyItemStateChanged(position, false);
+ private boolean attemptDeselect(String id) {
+ checkArgument(id != null);
+ if (notifyBeforeItemStateChange(id, false)) {
+ mSelection.remove(id);
+ notifyItemStateChanged(id, false);
if (DEBUG) Log.d(TAG, "Selection after deselect: " + mSelection);
return true;
} else {
@@ -442,10 +456,10 @@
}
}
- private boolean notifyBeforeItemStateChange(int position, boolean nextState) {
+ private boolean notifyBeforeItemStateChange(String id, boolean nextState) {
int lastListener = mCallbacks.size() - 1;
for (int i = lastListener; i > -1; i--) {
- if (!mCallbacks.get(i).onBeforeItemStateChange(position, nextState)) {
+ if (!mCallbacks.get(i).onBeforeItemStateChange(id, nextState)) {
return false;
}
}
@@ -456,12 +470,13 @@
* Notifies registered listeners when the selection status of a single item
* (identified by {@code position}) changes.
*/
- private void notifyItemStateChanged(int position, boolean selected) {
+ private void notifyItemStateChanged(String id, boolean selected) {
+ checkArgument(id != null);
int lastListener = mCallbacks.size() - 1;
for (int i = lastListener; i > -1; i--) {
- mCallbacks.get(i).onItemStateChanged(position, selected);
+ mCallbacks.get(i).onItemStateChanged(id, selected);
}
- mAdapter.notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+ mAdapter.onItemSelectionChanged(id);
}
/**
@@ -583,65 +598,40 @@
*/
public static final class Selection {
- // This class tracks selected positions by managing two arrays: the saved selection, and
- // the total selection. Saved selections are those which have been completed by tapping an
- // item or by completing a band select operation. Provisional selections are selections
- // which have been temporarily created by an in-progress band select operation (once the
- // user releases the mouse button during a band select operation, the selected items
- // become saved). The total selection is the combination of both the saved selection and
- // the provisional selection. Tracking both separately is necessary to ensure that saved
- // selections do not become deselected when they are removed from the provisional selection;
- // for example, if item A is tapped (and selected), then an in-progress band select covers A
- // then uncovers A, A should still be selected as it has been saved. To ensure this
- // behavior, the saved selection must be tracked separately.
- private SparseBooleanArray mSavedSelection;
- private SparseBooleanArray mTotalSelection;
-
- public Selection() {
- mSavedSelection = new SparseBooleanArray();
- mTotalSelection = new SparseBooleanArray();
- }
+ // This class tracks selected items by managing two sets: the saved selection, and the total
+ // selection. Saved selections are those which have been completed by tapping an item or by
+ // completing a band select operation. Provisional selections are selections which have been
+ // temporarily created by an in-progress band select operation (once the user releases the
+ // mouse button during a band select operation, the selected items become saved). The total
+ // selection is the combination of both the saved selection and the provisional
+ // selection. Tracking both separately is necessary to ensure that saved selections do not
+ // become deselected when they are removed from the provisional selection; for example, if
+ // item A is tapped (and selected), then an in-progress band select covers A then uncovers
+ // A, A should still be selected as it has been saved. To ensure this behavior, the saved
+ // selection must be tracked separately.
+ private Set<String> mSavedSelection = new HashSet<>();
+ private Set<String> mTotalSelection = new HashSet<>();
@VisibleForTesting
- public Selection(int... positions) {
- this();
- for (int i = 0; i < positions.length; i++) {
- add(positions[i]);
+ public Selection(String... ids) {
+ for (int i = 0; i < ids.length; i++) {
+ add(ids[i]);
}
}
/**
- * @param position
+ * @param id
* @return true if the position is currently selected.
*/
- public boolean contains(int position) {
- return mTotalSelection.get(position);
- }
-
- /**
- * Useful for iterating over selection. Please note that
- * iteration should be done over a copy of the selection,
- * not the live selection.
- *
- * @see #copyTo(MultiSelectManager.Selection)
- *
- * @param index
- * @return the position value stored at specified index.
- */
- public int get(int index) {
- return mTotalSelection.keyAt(index);
+ public boolean contains(@Nullable String id) {
+ return mTotalSelection.contains(id);
}
/**
* Returns an unordered array of selected positions.
*/
- public int[] getAll() {
- final int size = size();
- int[] positions = new int[size];
- for (int i = 0; i < size; i++) {
- positions[i] = get(i);
- }
- return positions;
+ public String[] getAll() {
+ return mTotalSelection.toArray(new String[0]);
}
/**
@@ -655,7 +645,7 @@
* @return true if the selection is empty.
*/
public boolean isEmpty() {
- return mTotalSelection.size() == 0;
+ return mTotalSelection.isEmpty();
}
/**
@@ -666,37 +656,34 @@
* contain a value of true, and entries which were removed contain a value of false.
*/
@VisibleForTesting
- protected SparseBooleanArray setProvisionalSelection(
- SparseBooleanArray provisionalSelection) {
- SparseBooleanArray delta = new SparseBooleanArray();
+ protected Map<String, Boolean> setProvisionalSelection(Set<String> provisionalSelection) {
+ Map<String, Boolean> delta = new HashMap<>();
- for (int i = 0; i < mTotalSelection.size(); i++) {
- int position = mTotalSelection.keyAt(i);
- if (!provisionalSelection.get(position) && !mSavedSelection.get(position)) {
- // Remove each item that used to be in the selection but is unsaved and not in
- // the new provisional selection.
- delta.put(position, false);
+ for (String id: mTotalSelection) {
+ // Mark each item that used to be in the selection but is unsaved and not in the new
+ // provisional selection.
+ if (!provisionalSelection.contains(id) && !mSavedSelection.contains(id)) {
+ delta.put(id, false);
}
}
- for (int i = 0; i < provisionalSelection.size(); i++) {
- int position = provisionalSelection.keyAt(i);
- if (!mTotalSelection.get(position)) {
- // Add each item that was not previously in the selection but is in the
- // new provisional selection.
- delta.put(position, true);
+ for (String id: provisionalSelection) {
+ // Mark each item that was not previously in the selection but is in the new
+ // provisional selection.
+ if (!mTotalSelection.contains(id)) {
+ delta.put(id, true);
}
}
- // Now, iterate through the changes and actually add/remove them to/from
- // mCurrentSelection. This could not be done in the previous loops because changing the
- // size of the selection mid-iteration changes iteration order erroneously.
- for (int i = 0; i < delta.size(); i++) {
- int position = delta.keyAt(i);
- if (delta.get(position)) {
- mTotalSelection.put(position, true);
+ // Now, iterate through the changes and actually add/remove them to/from the current
+ // selection. This could not be done in the previous loops because changing the size of
+ // the selection mid-iteration changes iteration order erroneously.
+ for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
+ String id = entry.getKey();
+ if (entry.getValue()) {
+ mTotalSelection.add(id);
} else {
- mTotalSelection.delete(position);
+ mTotalSelection.remove(id);
}
}
@@ -710,7 +697,7 @@
*/
@VisibleForTesting
protected void applyProvisionalSelection() {
- mSavedSelection = mTotalSelection.clone();
+ mSavedSelection = new HashSet<>(mTotalSelection);
}
/**
@@ -718,16 +705,16 @@
* now deselected.
*/
@VisibleForTesting
- protected void cancelProvisionalSelection() {
- mTotalSelection = mSavedSelection.clone();
+ void cancelProvisionalSelection() {
+ mTotalSelection = new HashSet<>(mSavedSelection);
}
/** @hide */
@VisibleForTesting
- boolean add(int position) {
- if (!mTotalSelection.get(position)) {
- mTotalSelection.put(position, true);
- mSavedSelection.put(position, true);
+ boolean add(String id) {
+ if (!mTotalSelection.contains(id)) {
+ mTotalSelection.add(id);
+ mSavedSelection.add(id);
return true;
}
return false;
@@ -735,79 +722,32 @@
/** @hide */
@VisibleForTesting
- boolean remove(int position) {
- if (mTotalSelection.get(position)) {
- mTotalSelection.delete(position);
- mSavedSelection.delete(position);
+ boolean remove(String id) {
+ if (mTotalSelection.contains(id)) {
+ mTotalSelection.remove(id);
+ mSavedSelection.remove(id);
return true;
}
return false;
}
- /**
- * Adjusts the selection range to reflect the existence of newly inserted values at
- * the specified positions. This has the effect of adjusting all existing selected
- * positions within the specified range accordingly. Note that this function discards any
- * provisional selections which may have been applied.
- *
- * @param startPosition
- * @param count
- * @hide
- */
- @VisibleForTesting
- void expand(int startPosition, int count) {
- checkState(startPosition >= 0);
- checkState(count > 0);
- cancelProvisionalSelection();
-
- for (int i = 0; i < mTotalSelection.size(); i++) {
- int itemPosition = mTotalSelection.keyAt(i);
- if (itemPosition >= startPosition) {
- mTotalSelection.setKeyAt(i, itemPosition + count);
- mSavedSelection.setKeyAt(i, itemPosition + count);
- }
- }
- }
-
- /**
- * Adjusts the selection range to reflect the removal specified positions. This has
- * the effect of adjusting all existing selected positions within the specified range
- * accordingly. Note that this function discards any provisional selections which may have
- * been applied.
- *
- * @param startPosition
- * @param count The length of the range to collapse. Must be greater than 0.
- * @hide
- */
- @VisibleForTesting
- void collapse(int startPosition, int count) {
- checkState(startPosition >= 0);
- checkState(count > 0);
-
- int endPosition = startPosition + count - 1;
-
- SparseBooleanArray newSelection = new SparseBooleanArray();
- for (int i = 0; i < mSavedSelection.size(); i++) {
- int itemPosition = mSavedSelection.keyAt(i);
- if (itemPosition < startPosition) {
- newSelection.append(itemPosition, true);
- } else if (itemPosition > endPosition) {
- newSelection.append(itemPosition - count, true);
- }
- }
- mSavedSelection = newSelection;
- cancelProvisionalSelection();
- }
-
public void clear() {
mSavedSelection.clear();
mTotalSelection.clear();
}
+ /**
+ * Trims this selection to be the intersection of itself with the set of given IDs.
+ */
+ public void intersect(Collection<String> ids) {
+ mSavedSelection.retainAll(ids);
+ mTotalSelection.retainAll(ids);
+ }
+
@VisibleForTesting
void copyFrom(Selection source) {
- mSavedSelection = source.mSavedSelection.clone();
- mTotalSelection = source.mTotalSelection.clone();
+ mSavedSelection = new HashSet<>(source.mSavedSelection);
+ mTotalSelection = new HashSet<>(source.mTotalSelection);
}
@Override
@@ -821,11 +761,11 @@
.append(mTotalSelection.size())
.append(", ")
.append("items=[");
- for (int i=0; i < mTotalSelection.size(); i++) {
- if (i > 0) {
+ for (Iterator<String> i = mTotalSelection.iterator(); i.hasNext(); ) {
+ buffer.append(i.next());
+ if (i.hasNext()) {
buffer.append(", ");
}
- buffer.append(mTotalSelection.keyAt(i));
}
buffer.append("]}");
return buffer.toString();
@@ -884,8 +824,8 @@
private boolean mIsOverlayShown = false;
- RuntimeSelectionEnvironment(RecyclerView rv) {
- mView = rv;
+ RuntimeSelectionEnvironment(RecyclerView view) {
+ mView = view;
mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
}
@@ -904,12 +844,12 @@
}
@Override
- public void addOnScrollListener(OnScrollListener listener) {
+ public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
mView.addOnScrollListener(listener);
}
@Override
- public void removeOnScrollListener(OnScrollListener listener) {
+ public void removeOnScrollListener(RecyclerView.OnScrollListener listener) {
mView.removeOnScrollListener(listener);
}
@@ -943,7 +883,7 @@
@Override
public int getColumnCount() {
- LayoutManager layoutManager = mView.getLayoutManager();
+ RecyclerView.LayoutManager layoutManager = mView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
return ((GridLayoutManager) layoutManager).getSpanCount();
}
@@ -1005,16 +945,27 @@
if (vh != null) {
vh.itemView.requestFocus();
} else {
- // Don't smooth scroll; that taxes the system unnecessarily and makes the scroll
- // handling logic below more complicated. See b/24865658.
- mView.scrollToPosition(pos);
+ mView.smoothScrollToPosition(pos);
// Set a one-time listener to request focus when the scroll has completed.
mView.addOnScrollListener(
new RecyclerView.OnScrollListener() {
@Override
- public void onScrolled(RecyclerView view, int dx, int dy) {
- view.findViewHolderForAdapterPosition(pos).itemView.requestFocus();
- view.removeOnScrollListener(this);
+ public void onScrollStateChanged (RecyclerView view, int newState) {
+ if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+ // When scrolling stops, find the item and focus it.
+ RecyclerView.ViewHolder vh =
+ view.findViewHolderForAdapterPosition(pos);
+ if (vh != null) {
+ vh.itemView.requestFocus();
+ } else {
+ // This might happen in weird corner cases, e.g. if the user is
+ // scrolling while a delete operation is in progress. In that
+ // case, just don't attempt to focus the missing item.
+ Log.w(
+ TAG, "Unable to focus position " + pos + " after a scroll");
+ }
+ view.removeOnScrollListener(this);
+ }
}
});
}
@@ -1029,17 +980,17 @@
* @param selected <code>true</code> if the item is now selected, <code>false</code>
* if the item is now unselected.
*/
- public void onItemStateChanged(int position, boolean selected);
+ public void onItemStateChanged(String id, boolean selected);
/**
* Called prior to an item changing state. Callbacks can cancel
* the change at {@code position} by returning {@code false}.
*
- * @param position Adapter position of the item that was checked or unchecked
+ * @param id Adapter position of the item that was checked or unchecked
* @param selected <code>true</code> if the item is to be selected, <code>false</code>
* if the item is to be unselected.
*/
- public boolean onBeforeItemStateChange(int position, boolean selected);
+ public boolean onBeforeItemStateChange(String id, boolean selected);
/**
* Called immediately after completion of any set of changes.
@@ -1075,7 +1026,7 @@
mModelBuilder = new Runnable() {
@Override
public void run() {
- mModel = new GridModel(mEnvironment);
+ mModel = new GridModel(mEnvironment, mAdapter);
mModel.addOnSelectionChangedListener(BandController.this);
}
};
@@ -1202,11 +1153,15 @@
mSelection.applyProvisionalSelection();
mModel.endSelection();
int firstSelected = mModel.getPositionNearestOrigin();
- if (!mSelection.contains(firstSelected)) {
- Log.w(TAG, "First selected by band is NOT in selection!");
- // Sadly this is really happening. Need to figure out what's going on.
- } else if (firstSelected != GridModel.NOT_SET) {
- setSelectionFocusBegin(firstSelected);
+ if (firstSelected != NOT_SET) {
+ if (mSelection.contains(mAdapter.getModelId(firstSelected))) {
+ // TODO: firstSelected should really be lastSelected, we want to anchor the item
+ // where the mouse-up occurred.
+ setSelectionRangeBegin(firstSelected);
+ } else {
+ // TODO: Check if this is really happening.
+ Log.w(TAG, "First selected by band is NOT in selection!");
+ }
}
mModel = null;
@@ -1214,11 +1169,10 @@
}
@Override
- public void onSelectionChanged(SparseBooleanArray updatedSelection) {
- SparseBooleanArray delta = mSelection.setProvisionalSelection(updatedSelection);
- for (int i = 0; i < delta.size(); i++) {
- int position = delta.keyAt(i);
- notifyItemStateChanged(position, delta.get(position));
+ public void onSelectionChanged(Set<String> updatedSelection) {
+ Map<String, Boolean> delta = mSelection.setProvisionalSelection(updatedSelection);
+ for (Map.Entry<String, Boolean> entry: delta.entrySet()) {
+ notifyItemStateChanged(entry.getKey(), entry.getValue());
}
notifySelectionChanged();
}
@@ -1362,6 +1316,8 @@
private static final int LOWER_RIGHT = LOWER | RIGHT;
private final SelectionEnvironment mHelper;
+ private final DocumentsAdapter mAdapter;
+
private final List<OnSelectionChangedListener> mOnSelectionChangedListeners =
new ArrayList<>();
@@ -1384,7 +1340,7 @@
// Array passed to registered OnSelectionChangedListeners. One array is created and reused
// throughout the lifetime of the object.
- private final SparseBooleanArray mSelection = new SparseBooleanArray();
+ private final Set<String> mSelection = new HashSet<>();
// The current pointer (in absolute positioning from the top of the view).
private Point mPointer = null;
@@ -1399,8 +1355,9 @@
// should expand from when Shift+click is used.
private int mPositionNearestOrigin = NOT_SET;
- GridModel(SelectionEnvironment helper) {
+ GridModel(SelectionEnvironment helper, DocumentsAdapter adapter) {
mHelper = helper;
+ mAdapter = adapter;
mHelper.addOnScrollListener(this);
}
@@ -1478,8 +1435,7 @@
int adapterPosition = mHelper.getAdapterPositionAt(i);
if (!mKnownPositions.get(adapterPosition)) {
mKnownPositions.put(adapterPosition, true);
- recordItemData(
- mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
+ recordItemData(mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
}
}
}
@@ -1600,13 +1556,22 @@
for (int column = columnStartIndex; column <= columnEndIndex; column++) {
SparseIntArray items = mColumns.get(mColumnBounds.get(column).lowerLimit);
for (int row = rowStartIndex; row <= rowEndIndex; row++) {
- int position = items.get(items.keyAt(row));
- mSelection.append(position, true);
- if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
- row, rowStartIndex, rowEndIndex)) {
- // If this is the position nearest the origin, record it now so that it
- // can be returned by endSelection() later.
- mPositionNearestOrigin = position;
+ // The default return value for SparseIntArray.get is 0, which is a valid
+ // position. Use a sentry value to prevent erroneously selecting item 0.
+ int position = items.get(items.keyAt(row), NOT_SET);
+ if (position != NOT_SET) {
+ String id = mAdapter.getModelId(position);
+ if (id != null) {
+ // The adapter inserts items for UI layout purposes that aren't associated
+ // with files. Those will have a null model ID. Don't select them.
+ mSelection.add(id);
+ }
+ if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
+ row, rowStartIndex, rowEndIndex)) {
+ // If this is the position nearest the origin, record it now so that it
+ // can be returned by endSelection() later.
+ mPositionNearestOrigin = position;
+ }
}
}
}
@@ -1643,7 +1608,7 @@
* Listener for changes in which items have been band selected.
*/
static interface OnSelectionChangedListener {
- public void onSelectionChanged(SparseBooleanArray updatedSelection);
+ public void onSelectionChanged(Set<String> updatedSelection);
}
void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
@@ -1965,18 +1930,23 @@
return false;
}
- return attemptChangePosition(position, event.isShiftPressed());
+ return attemptChangeFocus(position, event.isShiftPressed());
}
+ /**
+ * @param targetPosition The adapter position to focus.
+ * @param extendSelection
+ */
@VisibleForTesting
- boolean attemptChangePosition(int targetPosition, boolean isShiftPressed) {
+ boolean attemptChangeFocus(int targetPosition, boolean extendSelection) {
// Focus the new file.
mEnvironment.focusItem(targetPosition);
- if (isShiftPressed) {
+ if (extendSelection) {
if (!hasSelection()) {
// If there is no selection, start a selection when the user presses shift-arrow.
toggleSelection(targetPosition);
+ setSelectionRangeBegin(targetPosition);
} else if (!mSingleSelect) {
mRanger.snapSelection(targetPosition);
notifySelectionChanged();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
new file mode 100644
index 0000000..b4782f0
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * Adapter wrapper that inserts a sort of line break item between directories and regular files.
+ * Only needs to be used in GRID mode...at this time.
+ */
+final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
+
+ private static final String TAG = "SectionBreakDocumentsAdapterWrapper";
+ private static final int ITEM_TYPE_SECTION_BREAK = Integer.MAX_VALUE;
+
+ private final Environment mEnv;
+ private final DocumentsAdapter mDelegate;
+
+ private int mBreakPosition = -1;
+
+ SectionBreakDocumentsAdapterWrapper(Environment environment, DocumentsAdapter delegate) {
+ mEnv = environment;
+ mDelegate = delegate;
+
+ // Relay events published by our delegate to our listeners (presumably RecyclerView)
+ // with adjusted positions.
+ mDelegate.registerAdapterDataObserver(new EventRelay());
+ }
+
+ public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+ return new GridLayoutManager.SpanSizeLookup() {
+ @Override
+ public int getSpanSize(int position) {
+ // Make layout whitespace span the grid. This has the effect of breaking
+ // grid rows whenever layout whitespace is encountered.
+ if (getItemViewType(position) == ITEM_TYPE_SECTION_BREAK) {
+ return mEnv.getColumnCount();
+ } else {
+ return 1;
+ }
+ }
+ };
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ if (viewType == ITEM_TYPE_SECTION_BREAK) {
+ return new EmptyDocumentHolder(mEnv.getContext());
+ } else {
+ return mDelegate.createViewHolder(parent, viewType);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int p, List<Object> payload) {
+ if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+ mDelegate.onBindViewHolder(holder, toDelegatePosition(p), payload);
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int p) {
+ if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+ mDelegate.onBindViewHolder(holder, toDelegatePosition(p));
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return mBreakPosition == -1
+ ? mDelegate.getItemCount()
+ : mDelegate.getItemCount() + 1;
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ mDelegate.onModelUpdate(model);
+ mBreakPosition = -1;
+
+ // Walk down the list of IDs till we encounter something that's not a directory, and
+ // insert a whitespace element - this introduces a visual break in the grid between
+ // folders and documents.
+ // TODO: This code makes assumptions about the model, namely, that it performs a
+ // bucketed sort where directories will always be ordered before other files. CBB.
+ List<String> modelIds = mDelegate.getModelIds();
+ for (int i = 0; i < modelIds.size(); i++) {
+ if (!isDirectory(model, i)) {
+ mBreakPosition = i;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ mDelegate.onModelUpdateFailed(e);
+ }
+
+ @Override
+ public int getItemViewType(int p) {
+ if (p == mBreakPosition) {
+ return ITEM_TYPE_SECTION_BREAK;
+ } else {
+ return mDelegate.getItemViewType(toDelegatePosition(p));
+ }
+ }
+
+ /**
+ * Returns the position of an item in the delegate, adjusting
+ * values that are greater than the break position.
+ *
+ * @param p Position within the view
+ * @return Position within the delegate
+ */
+ private int toDelegatePosition(int p) {
+ return (mBreakPosition != -1 && p > mBreakPosition) ? p - 1 : p;
+ }
+
+ /**
+ * Returns the position of an item in the view, adjusting
+ * values that are greater than the break position.
+ *
+ * @param p Position within the delegate
+ * @return Position within the view
+ */
+ private int toViewPosition(int p) {
+ // If position is greater than or equal to the break, increase by one.
+ return (mBreakPosition != -1 && p >= mBreakPosition) ? p + 1 : p;
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ // NOTE: We hear about these changes and adjust break position
+ // in our AdapterDataObserver.
+ return mDelegate.hide(ids);
+ }
+
+ @Override
+ void unhide(SparseArray<String> ids) {
+ // NOTE: We hear about these changes and adjust break position
+ // in our AdapterDataObserver.
+ mDelegate.unhide(ids);
+ }
+
+ @Override
+ List<String> getModelIds() {
+ return mDelegate.getModelIds();
+ }
+
+ @Override
+ String getModelId(int p) {
+ return (p == mBreakPosition) ? null : mDelegate.getModelId(toDelegatePosition(p));
+ }
+
+ @Override
+ public void onItemSelectionChanged(String id) {
+ mDelegate.onItemSelectionChanged(id);
+ }
+
+ // Listener we add to our delegate. This allows us to relay events published
+ // by the delegate to our listeners (presumably RecyclerView) with adjusted positions.
+ private final class EventRelay extends AdapterDataObserver {
+ public void onChanged() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+ checkArgument(itemCount == 1);
+ notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
+ }
+
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ checkArgument(itemCount == 1);
+ if (positionStart < mBreakPosition) {
+ mBreakPosition++;
+ }
+ notifyItemRangeInserted(toViewPosition(positionStart), itemCount);
+ }
+
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ checkArgument(itemCount == 1);
+ if (positionStart < mBreakPosition) {
+ mBreakPosition--;
+ }
+ notifyItemRangeRemoved(toViewPosition(positionStart), itemCount);
+ }
+
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 215c6e6..83df18c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -255,10 +255,6 @@
return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
}
- public boolean isTypedDocument() {
- return (flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) != 0;
- }
-
public int hashCode() {
return derivedUri.hashCode() + mimeType.hashCode();
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 4caa891..12c0b8f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -174,7 +174,7 @@
derivedIcon = R.drawable.ic_root_home;
derivedType = TYPE_LOCAL;
} else if (isExternalStorage()) {
- derivedIcon = R.drawable.ic_root_sdcard;
+ derivedIcon = R.drawable.ic_root_smartphone;
derivedType = TYPE_LOCAL;
} else if (isDownloads()) {
derivedIcon = R.drawable.ic_root_download;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java
index 079d599..4ce0185 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java
@@ -97,7 +97,7 @@
public void testCopyFile() throws Exception {
String srcPath = "/test0.txt";
- Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
+ Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain",
"The five boxing wizards jump quickly".getBytes());
startService(createCopyIntent(Lists.newArrayList(testFile)));
@@ -110,10 +110,33 @@
assertCopied(srcPath);
}
+ public void testCopyVirtualTypedFile() throws Exception {
+ String srcPath = "/virtual.sth";
+ String expectedDstPath = "/virtual.sth.pdf";
+ ArrayList<String> streamTypes = new ArrayList<>();
+ streamTypes.add("application/pdf");
+ streamTypes.add("text/html");
+ String testContent = "I love fruit cakes!";
+ Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type",
+ streamTypes, testContent.getBytes());
+
+ startService(createCopyIntent(Lists.newArrayList(testFile)));
+
+ // 2 operations: file creation, then writing data.
+ mResolver.waitForChanges(2);
+
+ // Verify that one file was copied.
+ assertDestFileCount(1);
+
+ byte[] dstContent = readFile(DST_ROOT, expectedDstPath);
+ MoreAsserts.assertEquals("Moved file contents differ", testContent.getBytes(), dstContent);
+ }
+
public void testMoveFile() throws Exception {
String srcPath = "/test0.txt";
String testContent = "The five boxing wizards jump quickly";
- Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", testContent.getBytes());
+ Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain",
+ testContent.getBytes());
Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
@@ -142,9 +165,12 @@
"/test2.txt"
};
List<Uri> testFiles = Lists.newArrayList(
- mStorage.createFile(SRC_ROOT, srcPaths[0], "text/plain", testContent[0].getBytes()),
- mStorage.createFile(SRC_ROOT, srcPaths[1], "text/plain", testContent[1].getBytes()),
- mStorage.createFile(SRC_ROOT, srcPaths[2], "text/plain", testContent[2].getBytes()));
+ mStorage.createRegularFile(SRC_ROOT, srcPaths[0], "text/plain",
+ testContent[0].getBytes()),
+ mStorage.createRegularFile(SRC_ROOT, srcPaths[1], "text/plain",
+ testContent[1].getBytes()),
+ mStorage.createRegularFile(SRC_ROOT, srcPaths[2], "text/plain",
+ testContent[2].getBytes()));
// Copy all the test files.
startService(createCopyIntent(testFiles));
@@ -195,7 +221,6 @@
Intent intent = createCopyIntent(Lists.newArrayList(testDir), descDir);
startService(intent);
-
getService().addFinishedListener(mListener);
mListener.waitForFinished();
@@ -240,9 +265,9 @@
};
// Create test dir; put some files in it.
Uri testDir = createTestDirectory(srcDir);
- mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
- mStorage.createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
- mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
+ mStorage.createRegularFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
+ mStorage.createRegularFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
+ mStorage.createRegularFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
@@ -270,7 +295,7 @@
public void testCopyFileWithReadErrors() throws Exception {
String srcPath = "/test0.txt";
- Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
+ Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain",
"The five boxing wizards jump quickly".getBytes());
mStorage.simulateReadErrorsForFile(testFile);
@@ -284,9 +309,24 @@
assertDestFileCount(0);
}
+ public void testCopyVirtualNonTypedFile() throws Exception {
+ String srcPath = "/non-typed.sth";
+ Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type",
+ null /* streamTypes */, "I love Tokyo!".getBytes());
+
+ Intent intent = createCopyIntent(Lists.newArrayList(testFile));
+ startService(intent);
+ getService().addFinishedListener(mListener);
+
+ mListener.waitForFinished();
+ mListener.assertFailedCount(1);
+ mListener.assertFileFailed("non-typed.sth");
+ assertDestFileCount(0);
+ }
+
public void testMoveFileWithReadErrors() throws Exception {
String srcPath = "/test0.txt";
- Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain",
+ Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain",
"The five boxing wizards jump quickly".getBytes());
mStorage.simulateReadErrorsForFile(testFile);
@@ -326,10 +366,10 @@
};
// Create test dir; put some files in it.
Uri testDir = createTestDirectory(srcDir);
- mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
+ mStorage.createRegularFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes());
Uri errFile = mStorage
- .createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
- mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
+ .createRegularFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes());
+ mStorage.createRegularFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes());
mStorage.simulateReadErrorsForFile(errFile);
@@ -363,7 +403,7 @@
}
private Uri createTestDirectory(String dir) throws IOException {
- return mStorage.createFile(
+ return mStorage.createRegularFile(
SRC_ROOT, dir, DocumentsContract.Document.MIME_TYPE_DIR, null);
}
@@ -473,6 +513,7 @@
final CountDownLatch latch = new CountDownLatch(1);
final List<DocumentInfo> failedDocs = new ArrayList<>();
+
@Override
public void onFinished(List<DocumentInfo> failed) {
failedDocs.addAll(failed);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index 7a75503..50f4628 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -44,9 +44,11 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
public class StubProvider extends DocumentsProvider {
@@ -59,7 +61,7 @@
private static final String EXTRA_SIZE = "com.android.documentsui.stubprovider.SIZE";
private static final String EXTRA_ROOT = "com.android.documentsui.stubprovider.ROOT";
private static final String STORAGE_SIZE_KEY = "documentsui.stubprovider.size";
- private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100; // 100 MB.
+ private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100; // 100 MB.
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
@@ -105,7 +107,13 @@
mRoots.clear();
for (String rootId : rootIds) {
- final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
+ // Make a subdir in the cache dir for each root.
+ final File file = new File(getContext().getCacheDir(), rootId);
+ if (file.mkdir()) {
+ Log.i(TAG, "Created new root directory @ " + file.getPath());
+ }
+ final RootInfo rootInfo = new RootInfo(file, getSize(rootId));
+ mStorage.put(rootInfo.document.documentId, rootInfo.document);
mRoots.put(rootId, rootInfo);
}
}
@@ -188,7 +196,7 @@
created = file.createNewFile();
} catch (IOException e) {
// We'll throw an FNF exception later :)
- Log.e(TAG, "createnewFile operation failed for file: " + file, e);
+ Log.e(TAG, "createNewFile operation failed for file: " + file, e);
}
if (!created) {
throw new FileNotFoundException(
@@ -197,7 +205,8 @@
Log.i(TAG, "Created new file: " + file);
}
- final StubDocument document = new StubDocument(file, mimeType, parent);
+ final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent);
+ mStorage.put(document.documentId, document);
Log.d(TAG, "Created document " + document.documentId);
notifyParentChanged(document.parentId);
getContext().getContentResolver().notifyChange(
@@ -264,14 +273,18 @@
public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
throws FileNotFoundException {
final StubDocument document = mStorage.get(docId);
- if (document == null || !document.file.isFile())
+ if (document == null || !document.file.isFile()) {
throw new FileNotFoundException();
+ }
+ if ((document.flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0) {
+ throw new IllegalStateException("Tried to open a virtual file.");
+ }
if ("r".equals(mode)) {
- ParcelFileDescriptor pfd = ParcelFileDescriptor.open(document.file,
- ParcelFileDescriptor.MODE_READ_ONLY);
+ final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(document.file,
+ ParcelFileDescriptor.MODE_READ_ONLY);
if (docId.equals(mSimulateReadErrors)) {
- pfd = new ParcelFileDescriptor(pfd) {
+ return new ParcelFileDescriptor(pfd) {
@Override
public void checkError() throws IOException {
throw new IOException("Test error");
@@ -298,6 +311,51 @@
throw new FileNotFoundException();
}
+ @Override
+ public AssetFileDescriptor openTypedDocument(
+ String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
+ throws FileNotFoundException {
+ final StubDocument document = mStorage.get(documentId);
+ if (document == null || !document.file.isFile() || document.streamTypes == null) {
+ throw new FileNotFoundException();
+ }
+ for (final String mimeType : document.streamTypes) {
+ // Strict compare won't accept wildcards, but that's OK for tests, as DocumentsUI
+ // doesn't use them for getStreamTypes nor openTypedDocument.
+ if (mimeType.equals(mimeTypeFilter)) {
+ ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ document.file, ParcelFileDescriptor.MODE_READ_ONLY);
+ if (documentId.equals(mSimulateReadErrors)) {
+ pfd = new ParcelFileDescriptor(pfd) {
+ @Override
+ public void checkError() throws IOException {
+ throw new IOException("Test error");
+ }
+ };
+ }
+ return new AssetFileDescriptor(pfd, 0, document.file.length());
+ }
+ }
+ throw new IllegalArgumentException("Invalid MIME type filter for openTypedDocument().");
+ }
+
+ @Override
+ public String[] getStreamTypes(Uri uri, String mimeTypeFilter) {
+ final StubDocument document = mStorage.get(DocumentsContract.getDocumentId(uri));
+ if (document == null) {
+ throw new IllegalArgumentException(
+ "The provided Uri is incorrect, or the file is gone.");
+ }
+ if (!"*/*".equals(mimeTypeFilter)) {
+ // Not used by DocumentsUI, so don't bother implementing it.
+ throw new UnsupportedOperationException();
+ }
+ if (document.streamTypes == null) {
+ return null;
+ }
+ return document.streamTypes.toArray(new String[document.streamTypes.size()]);
+ }
+
private ParcelFileDescriptor startWrite(final StubDocument document)
throws FileNotFoundException {
ParcelFileDescriptor[] pipe;
@@ -398,14 +456,7 @@
row.add(Document.COLUMN_DISPLAY_NAME, document.file.getName());
row.add(Document.COLUMN_SIZE, document.file.length());
row.add(Document.COLUMN_MIME_TYPE, document.mimeType);
- int flags = Document.FLAG_SUPPORTS_DELETE;
- // TODO: Add support for renaming.
- if (document.file.isDirectory()) {
- flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
- } else {
- flags |= Document.FLAG_SUPPORTS_WRITE;
- }
- row.add(Document.COLUMN_FLAGS, flags);
+ row.add(Document.COLUMN_FLAGS, document.flags);
row.add(Document.COLUMN_LAST_MODIFIED, document.file.lastModified());
}
@@ -439,37 +490,30 @@
}
@VisibleForTesting
- public Uri createFile(String rootId, String path, String mimeType, byte[] content)
+ public Uri createRegularFile(String rootId, String path, String mimeType, byte[] content)
throws FileNotFoundException, IOException {
- Log.d(TAG, "Creating test file " + rootId + ":" + path);
- StubDocument root = mRoots.get(rootId).document;
- if (root == null) {
- throw new FileNotFoundException("No roots with the ID " + rootId + " were found");
- }
- File file = new File(root.file, path.substring(1));
- StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
+ final File file = createFile(rootId, path, mimeType, content);
+ final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
if (parent == null) {
- parent = mStorage.get(createFile(rootId, file.getParentFile().getPath(),
- DocumentsContract.Document.MIME_TYPE_DIR, null));
- Log.d(TAG, "Created parent " + parent.documentId);
- } else {
- Log.d(TAG, "Found parent " + parent.documentId);
+ throw new FileNotFoundException("Parent not found.");
}
+ final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent);
+ mStorage.put(document.documentId, document);
+ return DocumentsContract.buildDocumentUri(mAuthority, document.documentId);
+ }
- if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
- if (!file.mkdirs()) {
- throw new FileNotFoundException("Couldn't create directory " + file.getPath());
- }
- } else {
- if (!file.createNewFile()) {
- throw new FileNotFoundException("Couldn't create file " + file.getPath());
- }
- // Add content to the file.
- FileOutputStream fout = new FileOutputStream(file);
- fout.write(content);
- fout.close();
+ @VisibleForTesting
+ public Uri createVirtualFile(
+ String rootId, String path, String mimeType, List<String> streamTypes, byte[] content)
+ throws FileNotFoundException, IOException {
+ final File file = createFile(rootId, path, mimeType, content);
+ final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile()));
+ if (parent == null) {
+ throw new FileNotFoundException("Parent not found.");
}
- final StubDocument document = new StubDocument(file, mimeType, parent);
+ final StubDocument document = StubDocument.createVirtualDocument(
+ file, mimeType, streamTypes, parent);
+ mStorage.put(document.documentId, document);
return DocumentsContract.buildDocumentUri(mAuthority, document.documentId);
}
@@ -489,21 +533,39 @@
return found.file;
}
- final class RootInfo {
+ private File createFile(String rootId, String path, String mimeType, byte[] content)
+ throws FileNotFoundException, IOException {
+ Log.d(TAG, "Creating test file " + rootId + ":" + path);
+ StubDocument root = mRoots.get(rootId).document;
+ if (root == null) {
+ throw new FileNotFoundException("No roots with the ID " + rootId + " were found");
+ }
+ final File file = new File(root.file, path.substring(1));
+ if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
+ if (!file.mkdirs()) {
+ throw new FileNotFoundException("Couldn't create directory " + file.getPath());
+ }
+ } else {
+ if (!file.createNewFile()) {
+ throw new FileNotFoundException("Couldn't create file " + file.getPath());
+ }
+ try (final FileOutputStream fout = new FileOutputStream(file)) {
+ fout.write(content);
+ }
+ }
+ return file;
+ }
+
+ final static class RootInfo {
public final String name;
public final StubDocument document;
public long capacity;
public long size;
- RootInfo(String name, long capacity) {
- this.name = name;
+ RootInfo(File file, long capacity) {
+ this.name = file.getName();
this.capacity = 1024 * 1024;
- // Make a subdir in the cache dir for each root.
- File file = new File(getContext().getCacheDir(), name);
- if (file.mkdir()) {
- Log.i(TAG, "Created new root directory @ " + file.getPath());
- }
- this.document = new StubDocument(file, Document.MIME_TYPE_DIR, this);
+ this.document = StubDocument.createRootDocument(file, this);
this.capacity = capacity;
this.size = 0;
}
@@ -513,38 +575,69 @@
}
}
- final class StubDocument {
+ final static class StubDocument {
public final File file;
- public final String mimeType;
public final String documentId;
+ public final String mimeType;
+ public final List<String> streamTypes;
+ public final int flags;
public final String parentId;
public final RootInfo rootInfo;
- StubDocument(File file, String mimeType, StubDocument parent) {
+ private StubDocument(
+ File file, String mimeType, List<String> streamTypes, int flags,
+ StubDocument parent) {
this.file = file;
- this.mimeType = mimeType;
this.documentId = getDocumentIdForFile(file);
+ this.mimeType = mimeType;
+ this.streamTypes = streamTypes;
+ this.flags = flags;
this.parentId = parent.documentId;
this.rootInfo = parent.rootInfo;
- mStorage.put(this.documentId, this);
}
- StubDocument(File file, String mimeType, RootInfo rootInfo) {
+ private StubDocument(File file, RootInfo rootInfo) {
this.file = file;
- this.mimeType = mimeType;
this.documentId = getDocumentIdForFile(file);
+ this.mimeType = Document.MIME_TYPE_DIR;
+ this.streamTypes = new ArrayList<String>();
+ this.flags = Document.FLAG_DIR_SUPPORTS_CREATE;
this.parentId = null;
this.rootInfo = rootInfo;
- mStorage.put(this.documentId, this);
}
+
+ public static StubDocument createRootDocument(File file, RootInfo rootInfo) {
+ return new StubDocument(file, rootInfo);
+ }
+
+ public static StubDocument createRegularDocument(
+ File file, String mimeType, StubDocument parent) {
+ int flags = Document.FLAG_SUPPORTS_DELETE;
+ if (file.isDirectory()) {
+ flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+ } else {
+ flags |= Document.FLAG_SUPPORTS_WRITE;
+ }
+ return new StubDocument(file, mimeType, new ArrayList<String>(), flags, parent);
+ }
+
+ public static StubDocument createVirtualDocument(
+ File file, String mimeType, List<String> streamTypes, StubDocument parent) {
+ int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE
+ | Document.FLAG_VIRTUAL_DOCUMENT;
+ return new StubDocument(file, mimeType, streamTypes, flags, parent);
+ }
+
@Override
public String toString() {
return "StubDocument{"
+ "path:" + file.getPath()
- + ", mimeType:" + mimeType
- + ", rootInfo:" + rootInfo
+ ", documentId:" + documentId
+ + ", mimeType:" + mimeType
+ + ", streamTypes:" + streamTypes.toString()
+ + ", flags:" + flags
+ ", parentId:" + parentId
+ + ", rootInfo:" + rootInfo
+ "}";
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java
deleted file mode 100644
index b250e5d..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/DirectoryFragmentModelTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.documentsui.dirlist;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.provider.DocumentsContract.Document;
-import android.support.v7.widget.RecyclerView;
-import android.test.AndroidTestCase;
-import android.test.mock.MockContentResolver;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.view.ViewGroup;
-
-import com.android.documentsui.DirectoryResult;
-import com.android.documentsui.dirlist.DirectoryFragment.Model;
-import com.android.documentsui.dirlist.MultiSelectManager.Selection;
-import com.android.documentsui.model.DocumentInfo;
-
-import java.util.List;
-
-@SmallTest
-public class DirectoryFragmentModelTest extends AndroidTestCase {
-
- private static final int ITEM_COUNT = 5;
- private static final String[] COLUMNS = new String[]{
- Document.COLUMN_DOCUMENT_ID
- };
- private static Cursor cursor;
-
- private Context mContext;
- private Model model;
-
- public void setUp() {
- setupTestContext();
-
- MatrixCursor c = new MatrixCursor(COLUMNS);
- for (int i = 0; i < ITEM_COUNT; ++i) {
- MatrixCursor.RowBuilder row = c.newRow();
- row.add(COLUMNS[0], i);
- }
- cursor = c;
-
- DirectoryResult r = new DirectoryResult();
- r.cursor = cursor;
-
- // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
- model = new Model(mContext, new DummyAdapter());
- model.addUpdateListener(new DummyListener());
- model.update(r);
- }
-
- // Tests that the item count is correct.
- public void testItemCount() {
- assertEquals(ITEM_COUNT, model.getItemCount());
- }
-
- // Tests that the item count is correct after a deletion.
- public void testItemCount_WithDeletion() {
- // Simulate deleting 2 files.
- delete(2, 4);
-
- assertEquals(ITEM_COUNT - 2, model.getItemCount());
- }
-
- // Tests that the item count is correct after a deletion is undone.
- public void testItemCount_WithUndoneDeletion() {
- // Simulate deleting 2 files.
- delete(0, 3);
-
- // Undo the deletion
- model.undoDeletion();
- assertEquals(ITEM_COUNT, model.getItemCount());
- }
-
- // Tests that the right things are marked for deletion.
- public void testMarkForDeletion() {
- delete(1, 3);
-
- List<DocumentInfo> docs = model.getDocumentsMarkedForDeletion();
- assertEquals(2, docs.size());
- assertEquals("1", docs.get(0).documentId);
- assertEquals("3", docs.get(1).documentId);
- }
-
- // Tests the base case for Model.getItem.
- public void testGetItem() {
- for (int i = 0; i < ITEM_COUNT; ++i) {
- Cursor c = model.getItem(i);
- assertEquals(i, c.getPosition());
- }
- }
-
- // Tests that Model.getItem returns the right items after a deletion.
- public void testGetItem_WithDeletion() {
- // Simulate deleting 2 files.
- delete(2, 3);
-
- List<DocumentInfo> docs = getDocumentInfo(0, 1, 2);
- assertEquals("0", docs.get(0).documentId);
- assertEquals("1", docs.get(1).documentId);
- assertEquals("4", docs.get(2).documentId);
- }
-
- // Tests that Model.getItem returns the right items after a deletion is undone.
- public void testGetItem_WithCancelledDeletion() {
- delete(0, 1);
- model.undoDeletion();
-
- // Test that all documents are accounted for, in the right position.
- for (int i = 0; i < ITEM_COUNT; ++i) {
- assertEquals(Integer.toString(i), getDocumentInfo(i).get(0).documentId);
- }
- }
-
- private void setupTestContext() {
- final MockContentResolver resolver = new MockContentResolver();
- mContext = new ContextWrapper(getContext()) {
- @Override
- public ContentResolver getContentResolver() {
- return resolver;
- }
- };
- }
-
- private void delete(int... positions) {
- model.markForDeletion(new Selection(positions));
- }
-
- private List<DocumentInfo> getDocumentInfo(int... positions) {
- return model.getDocuments(new Selection(positions));
- }
-
- private static class DummyListener extends Model.UpdateListener {
- public void onModelUpdate(Model model) {}
- public void onModelUpdateFailed(Exception e) {}
- }
-
- private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
- public int getItemCount() { return 0; }
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return null;
- }
- }
-}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
new file mode 100644
index 0000000..5ce1823
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import java.util.List;
+
+@SmallTest
+public class ModelBackedDocumentsAdapterTest extends AndroidTestCase {
+
+ private static final String AUTHORITY = "test_authority";
+ private static final String[] NAMES = new String[] {
+ "4",
+ "foo",
+ "1",
+ "bar",
+ "*(Ljifl;a",
+ "0",
+ "baz",
+ "2",
+ "3",
+ "%$%VD"
+ };
+
+ private TestModel mModel;
+ private ModelBackedDocumentsAdapter mAdapter;
+
+ public void setUp() {
+
+ final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY);
+ mModel = new TestModel(testContext, AUTHORITY);
+ mModel.update(NAMES);
+
+ DocumentsAdapter.Environment env = new TestEnvironment(testContext);
+
+ mAdapter = new ModelBackedDocumentsAdapter(
+ env, new IconHelper(testContext, State.MODE_GRID));
+ mAdapter.onModelUpdate(mModel);
+ }
+
+ // Tests that the item count is correct.
+ public void testItemCount() {
+ assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+ }
+
+ // Tests that the item count is correct.
+ public void testHide_ItemCount() {
+ List<String> ids = mModel.getModelIds();
+ mAdapter.hide(ids.get(0), ids.get(1));
+ assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
+ }
+
+ // Tests that the items can be hidden and unhidden.
+ public void testUnhide_ItemCount() {
+ List<String> ids = mModel.getModelIds();
+ SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
+ mAdapter.unhide(hidden);
+ assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+ }
+
+ // Tests that the items can be hidden and unhidden.
+ public void testUnhide_PreservesOrder() {
+ List<String> ids = mModel.getModelIds();
+ SparseArray<String> hidden = mAdapter.hide(
+ ids.get(0), ids.get(1), ids.get(5), ids.get(9));
+ mAdapter.unhide(hidden);
+
+ // Finally ensure the restored items are in the original order
+ // by checking them against the model.
+ for (int i = 0; i < mAdapter.getItemCount(); i++) {
+ assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
+ }
+ }
+
+ private final class TestEnvironment implements DocumentsAdapter.Environment {
+ private final Context testContext;
+
+ private TestEnvironment(Context testContext) {
+ this.testContext = testContext;
+ }
+
+ @Override
+ public boolean isSelected(String id) {
+ return false;
+ }
+
+ @Override
+ public boolean isDocumentEnabled(String mimeType, int flags) {
+ return true;
+ }
+
+ @Override
+ public void initDocumentHolder(DocumentHolder holder) {}
+
+ @Override
+ public Model getModel() {
+ return mModel;
+ }
+
+ @Override
+ public State getDisplayState() {
+ return null;
+ }
+
+ @Override
+ public Context getContext() {
+ return testContext;
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 4;
+ }
+
+ @Override
+ public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {}
+ }
+
+ private static class DummyListener implements Model.UpdateListener {
+ public void onModelUpdate(Model model) {}
+ public void onModelUpdateFailed(Exception e) {}
+ }
+
+ private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ public int getItemCount() { return 0; }
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return null;
+ }
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
new file mode 100644
index 0000000..bed7c9c
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.State;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+@SmallTest
+public class ModelTest extends AndroidTestCase {
+
+ private static final int ITEM_COUNT = 10;
+ private static final String AUTHORITY = "test_authority";
+
+ private static final String[] COLUMNS = new String[]{
+ RootCursorWrapper.COLUMN_AUTHORITY,
+ Document.COLUMN_DOCUMENT_ID,
+ Document.COLUMN_FLAGS,
+ Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_SIZE,
+ Document.COLUMN_MIME_TYPE
+ };
+
+ private static final String[] NAMES = new String[] {
+ "4",
+ "foo",
+ "1",
+ "bar",
+ "*(Ljifl;a",
+ "0",
+ "baz",
+ "2",
+ "3",
+ "%$%VD"
+ };
+
+ private Cursor cursor;
+ private Context context;
+ private Model model;
+ private TestContentProvider provider;
+
+ public void setUp() {
+ setupTestContext();
+
+ Random rand = new Random();
+
+ MatrixCursor c = new MatrixCursor(COLUMNS);
+ for (int i = 0; i < ITEM_COUNT; ++i) {
+ MatrixCursor.RowBuilder row = c.newRow();
+ row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+ row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+ // Generate random document names and sizes. This forces the model's internal sort code
+ // to actually do something.
+ row.add(Document.COLUMN_DISPLAY_NAME, NAMES[i]);
+ row.add(Document.COLUMN_SIZE, rand.nextInt());
+ }
+ cursor = c;
+
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = cursor;
+
+ // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
+ model = new Model(context);
+ model.addUpdateListener(new DummyListener());
+ model.update(r);
+ }
+
+ // Tests that the model is properly emptied out after a null update.
+ public void testNullUpdate() {
+ model.update(null);
+
+ assertTrue(model.isEmpty());
+ assertEquals(0, model.getItemCount());
+ assertEquals(0, model.getModelIds().size());
+ }
+
+ // Tests that the item count is correct.
+ public void testItemCount() {
+ assertEquals(ITEM_COUNT, model.getItemCount());
+ }
+
+ // Tests multiple authorities with clashing document IDs.
+ public void testModelIdIsUnique() {
+ MatrixCursor cIn = new MatrixCursor(COLUMNS);
+
+ // Make two sets of items with the same IDs, under different authorities.
+ final String AUTHORITY0 = "auth0";
+ final String AUTHORITY1 = "auth1";
+ for (int i = 0; i < ITEM_COUNT; ++i) {
+ MatrixCursor.RowBuilder row0 = cIn.newRow();
+ row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0);
+ row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+
+ MatrixCursor.RowBuilder row1 = cIn.newRow();
+ row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1);
+ row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+ }
+
+ // Update the model, then make sure it contains all the expected items.
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = cIn;
+ model.update(r);
+
+ assertEquals(ITEM_COUNT * 2, model.getItemCount());
+ BitSet b0 = new BitSet(ITEM_COUNT);
+ BitSet b1 = new BitSet(ITEM_COUNT);
+
+ for (String id: model.getModelIds()) {
+ Cursor cOut = model.getItem(id);
+ String authority =
+ DocumentInfo.getCursorString(cOut, RootCursorWrapper.COLUMN_AUTHORITY);
+ String docId = DocumentInfo.getCursorString(cOut, Document.COLUMN_DOCUMENT_ID);
+
+ switch (authority) {
+ case AUTHORITY0:
+ b0.set(Integer.parseInt(docId));
+ break;
+ case AUTHORITY1:
+ b1.set(Integer.parseInt(docId));
+ break;
+ default:
+ fail("Unrecognized authority string");
+ }
+ }
+
+ assertEquals(ITEM_COUNT, b0.cardinality());
+ assertEquals(ITEM_COUNT, b1.cardinality());
+ }
+
+ // Tests the base case for Model.getItem.
+ public void testGetItem() {
+ List<String> ids = model.getModelIds();
+ assertEquals(ITEM_COUNT, ids.size());
+ for (int i = 0; i < ITEM_COUNT; ++i) {
+ Cursor c = model.getItem(ids.get(i));
+ assertEquals(i, c.getPosition());
+ }
+ }
+
+ // Tests sorting by item name.
+ public void testSort_names() {
+ BitSet seen = new BitSet(ITEM_COUNT);
+ List<String> names = new ArrayList<>();
+
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = cursor;
+ r.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
+ model.update(r);
+
+ for (String id: model.getModelIds()) {
+ Cursor c = model.getItem(id);
+ seen.set(c.getPosition());
+ names.add(DocumentInfo.getCursorString(c, Document.COLUMN_DISPLAY_NAME));
+ }
+
+ assertEquals(ITEM_COUNT, seen.cardinality());
+ for (int i = 0; i < names.size()-1; ++i) {
+ assertTrue(DocumentInfo.compareToIgnoreCaseNullable(names.get(i), names.get(i+1)) <= 0);
+ }
+ }
+
+ // Tests sorting by item size.
+ public void testSort_sizes() {
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = cursor;
+ r.sortOrder = State.SORT_ORDER_SIZE;
+ model.update(r);
+
+ BitSet seen = new BitSet(ITEM_COUNT);
+ int previousSize = Integer.MAX_VALUE;
+ for (String id: model.getModelIds()) {
+ Cursor c = model.getItem(id);
+ seen.set(c.getPosition());
+ // Check sort order - descending numerical
+ int size = DocumentInfo.getCursorInt(c, Document.COLUMN_SIZE);
+ assertTrue(previousSize >= size);
+ previousSize = size;
+ }
+ // Check that all items were accounted for.
+ assertEquals(ITEM_COUNT, seen.cardinality());
+ }
+
+ // Tests that directories and files are properly bucketed when sorting by size
+ public void testSort_sizesWithBucketing() {
+ MatrixCursor c = new MatrixCursor(COLUMNS);
+
+ for (int i = 0; i < ITEM_COUNT; ++i) {
+ MatrixCursor.RowBuilder row = c.newRow();
+ row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
+ row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+ row.add(Document.COLUMN_SIZE, i);
+ // Interleave directories and text files.
+ String mimeType =(i % 2 == 0) ? Document.MIME_TYPE_DIR : "text/*";
+ row.add(Document.COLUMN_MIME_TYPE, mimeType);
+ }
+
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = c;
+ r.sortOrder = State.SORT_ORDER_SIZE;
+ model.update(r);
+
+ boolean seenAllDirs = false;
+ int previousSize = Integer.MAX_VALUE;
+ BitSet seen = new BitSet(ITEM_COUNT);
+ // Iterate over items in sort order. Once we've encountered a document (i.e. not a
+ // directory), all subsequent items must also be documents. That is, all directories are
+ // bucketed at the front of the list, sorted by size, followed by documents, sorted by size.
+ for (String id: model.getModelIds()) {
+ Cursor cOut = model.getItem(id);
+ seen.set(cOut.getPosition());
+
+ String mimeType = DocumentInfo.getCursorString(cOut, Document.COLUMN_MIME_TYPE);
+ if (seenAllDirs) {
+ assertFalse(Document.MIME_TYPE_DIR.equals(mimeType));
+ } else {
+ if (!Document.MIME_TYPE_DIR.equals(mimeType)) {
+ seenAllDirs = true;
+ // Reset the previous size seen, because documents are bucketed separately by
+ // the sort.
+ previousSize = Integer.MAX_VALUE;
+ }
+ }
+ // Check sort order - descending numerical
+ int size = DocumentInfo.getCursorInt(c, Document.COLUMN_SIZE);
+ assertTrue(previousSize >= size);
+ previousSize = size;
+ }
+
+ // Check that all items were accounted for.
+ assertEquals(ITEM_COUNT, seen.cardinality());
+ }
+
+ // Tests that Model.delete works correctly.
+ public void testDelete() throws Exception {
+ // Simulate deleting 2 files.
+ List<DocumentInfo> docsBefore = getDocumentInfo(2, 3);
+ delete(2, 3);
+
+ provider.assertWasDeleted(docsBefore.get(0));
+ provider.assertWasDeleted(docsBefore.get(1));
+ }
+
+ private void setupTestContext() {
+ final MockContentResolver resolver = new MockContentResolver();
+ context = new ContextWrapper(getContext()) {
+ @Override
+ public ContentResolver getContentResolver() {
+ return resolver;
+ }
+ };
+ provider = new TestContentProvider();
+ resolver.addProvider(AUTHORITY, provider);
+ }
+
+ private Selection positionToSelection(int... positions) {
+ List<String> ids = model.getModelIds();
+ Selection s = new Selection();
+ // Construct a selection of the given positions.
+ for (int p: positions) {
+ s.add(ids.get(p));
+ }
+ return s;
+ }
+
+ private void delete(int... positions) throws InterruptedException {
+ Selection s = positionToSelection(positions);
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ model.delete(
+ s,
+ new Model.DeletionListener() {
+ @Override
+ public void onError() {
+ latch.countDown();
+ }
+ @Override
+ void onCompletion() {
+ latch.countDown();
+ }
+ });
+ latch.await();
+ }
+
+ private List<DocumentInfo> getDocumentInfo(int... positions) {
+ return model.getDocuments(positionToSelection(positions));
+ }
+
+ private static class DummyListener implements Model.UpdateListener {
+ public void onModelUpdate(Model model) {}
+ public void onModelUpdateFailed(Exception e) {}
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index b3d45ae..e06199e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -20,13 +20,11 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.SparseBooleanArray;
-import android.view.View;
-import android.view.ViewGroup;
import com.android.documentsui.TestInputEvent;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
-import org.mockito.Mockito;
+import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.HashSet;
@@ -39,30 +37,27 @@
private static final List<String> items;
static {
items = new ArrayList<String>();
- items.add("aaa");
- items.add("bbb");
- items.add("ccc");
- items.add("111");
- items.add("222");
- items.add("333");
+ for (int i = 0; i < 100; ++i) {
+ items.add(Integer.toString(i));
+ }
}
private MultiSelectManager mManager;
- private TestAdapter mAdapter;
private TestCallback mCallback;
private TestSelectionEnvironment mEnv;
+ private TestDocumentsAdapter mAdapter;
public void setUp() throws Exception {
- mAdapter = new TestAdapter(items);
mCallback = new TestCallback();
- mEnv = new TestSelectionEnvironment();
- mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_MULTIPLE);
+ mEnv = new TestSelectionEnvironment(items);
+ mAdapter = new TestDocumentsAdapter(items);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
mManager.addCallback(mCallback);
}
public void testMouseClick_StartsSelectionMode() {
click(7);
- assertSelection(7);
+ assertSelection(items.get(7));
}
public void testMouseClick_NotifiesSelectionChanged() {
@@ -84,21 +79,21 @@
}
public void testSetSelectionFocusBegin() {
- mManager.setItemSelected(7, true);
- mManager.setSelectionFocusBegin(7);
+ mManager.setItemsSelected(Lists.newArrayList(items.get(7)), true);
+ mManager.setSelectionRangeBegin(7);
shiftClick(11);
assertRangeSelection(7, 11);
}
public void testLongPress_StartsSelectionMode() {
longPress(7);
- assertSelection(7);
+ assertSelection(items.get(7));
}
public void testLongPress_SecondPressExtendsSelection() {
longPress(7);
longPress(99);
- assertSelection(7, 99);
+ assertSelection(items.get(7), items.get(99));
}
public void testSingleTapUp_UnselectsSelectedItem() {
@@ -118,8 +113,7 @@
longPress(99);
tap(7);
tap(13);
- tap(129899);
- assertSelection(7, 99, 13, 129899);
+ assertSelection(items.get(7), items.get(99), items.get(13));
}
public void testSingleTapUp_ShiftCreatesRangeSelection() {
@@ -173,27 +167,27 @@
}
public void testSingleSelectMode() {
- mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(20);
tap(13);
- assertSelection(13);
+ assertSelection(items.get(13));
}
public void testSingleSelectMode_ShiftTap() {
- mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(13);
shiftTap(20);
- assertSelection(20);
+ assertSelection(items.get(20));
}
public void testSingleSelectMode_ShiftDoesNotExtendSelection() {
- mManager = new MultiSelectManager(mAdapter, mEnv, MultiSelectManager.MODE_SINGLE);
+ mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
mManager.addCallback(mCallback);
longPress(20);
keyToPosition(22, true);
- assertSelection(22);
+ assertSelection(items.get(22));
}
public void testProvisionalSelection() {
@@ -203,26 +197,37 @@
SparseBooleanArray provisional = new SparseBooleanArray();
provisional.append(1, true);
provisional.append(2, true);
- s.setProvisionalSelection(provisional);
- assertSelection(1, 2);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(1), items.get(2));
provisional.delete(1);
provisional.append(3, true);
- s.setProvisionalSelection(provisional);
- assertSelection(2, 3);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(2), items.get(3));
s.applyProvisionalSelection();
- assertSelection(2, 3);
+ assertSelection(items.get(2), items.get(3));
provisional.clear();
provisional.append(3, true);
provisional.append(4, true);
- s.setProvisionalSelection(provisional);
- assertSelection(2, 3, 4);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(2), items.get(3), items.get(4));
provisional.delete(3);
- s.setProvisionalSelection(provisional);
- assertSelection(2, 3, 4);
+ s.setProvisionalSelection(getItemIds(provisional));
+ assertSelection(items.get(2), items.get(3), items.get(4));
+ }
+
+ private static Set<String> getItemIds(SparseBooleanArray selection) {
+ Set<String> ids = new HashSet<>();
+
+ int count = selection.size();
+ for (int i = 0; i < count; ++i) {
+ ids.add(items.get(selection.keyAt(i)));
+ }
+
+ return ids;
}
private void longPress(int position) {
@@ -246,26 +251,26 @@
}
private void keyToPosition(int position, boolean shift) {
- mManager.attemptChangePosition(position, shift);
+ mManager.attemptChangeFocus(position, shift);
}
- private void assertSelected(int... expected) {
+ private void assertSelected(String... expected) {
for (int i = 0; i < expected.length; i++) {
Selection selection = mManager.getSelection();
String err = String.format(
- "Selection %s does not contain %d", selection, expected[i]);
+ "Selection %s does not contain %s", selection, expected[i]);
assertTrue(err, selection.contains(expected[i]));
}
}
- private void assertSelection(int... expected) {
+ private void assertSelection(String... expected) {
assertSelectionSize(expected.length);
assertSelected(expected);
}
private void assertRangeSelected(int begin, int end) {
for (int i = begin; i <= end; i++) {
- assertSelected(i);
+ assertSelected(items.get(i));
}
}
@@ -281,15 +286,15 @@
private static final class TestCallback implements MultiSelectManager.Callback {
- Set<Integer> ignored = new HashSet<>();
+ Set<String> ignored = new HashSet<>();
private boolean mSelectionChanged = false;
@Override
- public void onItemStateChanged(int position, boolean selected) {}
+ public void onItemStateChanged(String modelId, boolean selected) {}
@Override
- public boolean onBeforeItemStateChange(int position, boolean selected) {
- return !ignored.contains(position);
+ public boolean onBeforeItemStateChange(String modelId, boolean selected) {
+ return !ignored.contains(modelId);
}
@Override
@@ -301,33 +306,4 @@
assertTrue(mSelectionChanged);
}
}
-
- private static final class TestHolder extends RecyclerView.ViewHolder {
- // each data item is just a string in this case
- public TestHolder(View view) {
- super(view);
- }
- }
-
- private static final class TestAdapter extends RecyclerView.Adapter<TestHolder> {
-
- private List<String> mItems;
-
- public TestAdapter(List<String> items) {
- mItems = items;
- }
-
- @Override
- public TestHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new TestHolder(Mockito.mock(ViewGroup.class));
- }
-
- @Override
- public void onBindViewHolder(TestHolder holder, int position) {}
-
- @Override
- public int getItemCount() {
- return mItems.size();
- }
- }
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index c856b22..5c04db9 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -16,16 +16,20 @@
package com.android.documentsui.dirlist;
+import static com.android.documentsui.dirlist.MultiSelectManager.GridModel.NOT_SET;
+
import android.graphics.Point;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.SparseBooleanArray;
import android.view.View;
import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
+import java.util.ArrayList;
+import java.util.Set;
+
@SmallTest
public class MultiSelectManager_GridModelTest extends AndroidTestCase {
@@ -33,19 +37,32 @@
private static final int CHILD_VIEW_EDGE_PX = 100;
private static final int VIEWPORT_HEIGHT = 500;
- private static GridModel model;
- private static TestEnvironment env;
- private static SparseBooleanArray lastSelection;
- private static int viewWidth;
+ private GridModel model;
+ private TestEnvironment env;
+ private TestDocumentsAdapter adapter;
+ private Set<String> lastSelection;
+ private int viewWidth;
- private static void setUp(int numChildren, int numColumns) {
+ private void initData(final int numChildren, int numColumns) {
env = new TestEnvironment(numChildren, numColumns);
+ adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
+ @Override
+ public String getModelId(int position) {
+ return Integer.toString(position);
+ }
+
+ @Override
+ public int getItemCount() {
+ return numChildren;
+ }
+ };
+
viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
- model = new GridModel(env);
+ model = new GridModel(env, adapter);
model.addOnSelectionChangedListener(
new GridModel.OnSelectionChangedListener() {
@Override
- public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+ public void onSelectionChanged(Set<String> updatedSelection) {
lastSelection = updatedSelection;
}
});
@@ -59,123 +76,123 @@
}
public void testSelectionLeftOfItems() {
- setUp(20, 5);
+ initData(20, 5);
model.startSelection(new Point(0, 10));
model.resizeSelection(new Point(1, 11));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionRightOfItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(viewWidth - 1, 10));
model.resizeSelection(new Point(viewWidth - 2, 11));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionAboveItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(10, 0));
model.resizeSelection(new Point(11, 1));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionBelowItems() {
- setUp(5, 4);
+ initData(5, 4);
model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testVerticalSelectionBetweenItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(106, 0));
model.resizeSelection(new Point(107, 200));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testHorizontalSelectionBetweenItems() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(0, 105));
model.resizeSelection(new Point(200, 106));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testGrowingAndShrinkingSelection() {
- setUp(20, 4);
+ initData(20, 4);
model.startSelection(new Point(0, 0));
model.resizeSelection(new Point(5, 5));
- assertSelected(new int[] {0});
+ assertSelected(0);
model.resizeSelection(new Point(109, 109));
- assertSelected(new int[] {0});
+ assertSelected(0);
model.resizeSelection(new Point(110, 109));
- assertSelected(new int[] {0, 1});
+ assertSelected(0, 1);
model.resizeSelection(new Point(110, 110));
- assertSelected(new int[] {0, 1, 4, 5});
+ assertSelected(0, 1, 4, 5);
model.resizeSelection(new Point(214, 214));
- assertSelected(new int[] {0, 1, 4, 5});
+ assertSelected(0, 1, 4, 5);
model.resizeSelection(new Point(215, 214));
- assertSelected(new int[] {0, 1, 2, 4, 5, 6});
+ assertSelected(0, 1, 2, 4, 5, 6);
model.resizeSelection(new Point(214, 214));
- assertSelected(new int[] {0, 1, 4, 5});
+ assertSelected(0, 1, 4, 5);
model.resizeSelection(new Point(110, 110));
- assertSelected(new int[] {0, 1, 4, 5});
+ assertSelected(0, 1, 4, 5);
model.resizeSelection(new Point(110, 109));
- assertSelected(new int[] {0, 1});
+ assertSelected(0, 1);
model.resizeSelection(new Point(109, 109));
- assertSelected(new int[] {0});
+ assertSelected(0);
model.resizeSelection(new Point(5, 5));
- assertSelected(new int[] {0});
+ assertSelected(0);
model.resizeSelection(new Point(0, 0));
- assertSelected(new int[0]);
- assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
+ assertSelected();
+ assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionMovingAroundOrigin() {
- setUp(16, 4);
+ initData(16, 4);
model.startSelection(new Point(210, 210));
model.resizeSelection(new Point(viewWidth - 1, 0));
- assertSelected(new int[] {2, 3, 6, 7});
+ assertSelected(2, 3, 6, 7);
model.resizeSelection(new Point(0, 0));
- assertSelected(new int[] {0, 1, 4, 5});
+ assertSelected(0, 1, 4, 5);
model.resizeSelection(new Point(0, 420));
- assertSelected(new int[] {8, 9, 12, 13});
+ assertSelected(8, 9, 12, 13);
model.resizeSelection(new Point(viewWidth - 1, 420));
- assertSelected(new int[] {10, 11, 14, 15});
+ assertSelected(10, 11, 14, 15);
assertEquals(10, model.getPositionNearestOrigin());
}
public void testScrollingBandSelect() {
- setUp(40, 4);
+ initData(40, 4);
model.startSelection(new Point(0, 0));
model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- assertSelected(new int[] {0, 4, 8, 12, 16});
+ assertSelected(0, 4, 8, 12, 16);
scroll(CHILD_VIEW_EDGE_PX);
- assertSelected(new int[] {0, 4, 8, 12, 16, 20});
+ assertSelected(0, 4, 8, 12, 16, 20);
model.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
- assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21});
+ assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21);
scroll(CHILD_VIEW_EDGE_PX);
- assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25});
+ assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25);
scroll(-2 * CHILD_VIEW_EDGE_PX);
- assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17});
+ assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17);
model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- assertSelected(new int[] {0, 4, 8, 12, 16});
+ assertSelected(0, 4, 8, 12, 16);
assertEquals(0, model.getPositionNearestOrigin());
}
- private static void assertSelected(int[] selectedPositions) {
+ private void assertSelected(int... selectedPositions) {
assertEquals(selectedPositions.length, lastSelection.size());
for (int position : selectedPositions) {
- assertTrue(lastSelection.get(position));
+ assertTrue(lastSelection.contains(Integer.toString(position)));
}
}
- private static void scroll(int dy) {
+ private void scroll(int dy) {
assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
env.verticalOffset += dy;
model.onScrolled(null, 0, dy);
@@ -246,7 +263,7 @@
@Override
public Rect getAbsoluteRectForChildViewAt(int index) {
- int adapterPosition = getAdapterPositionAt(index);
+ int adapterPosition = (getFirstVisibleRowIndex() * mNumColumns) + index;
int rowIndex = adapterPosition / mNumColumns;
int columnIndex = adapterPosition % mNumColumns;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
index 030ac6c..444b2dc 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_SelectionTest.java
@@ -20,33 +20,43 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+import com.google.common.collect.Sets;
+
+import java.util.HashSet;
+import java.util.Set;
@SmallTest
public class MultiSelectManager_SelectionTest extends AndroidTestCase {
private Selection selection;
+ private String[] ids = new String[]{
+ "foo",
+ "43",
+ "auth|id=@53di*/f3#d"
+ };
+
@Override
public void setUp() throws Exception {
selection = new Selection();
- selection.add(3);
- selection.add(5);
- selection.add(9);
+ selection.add(ids[0]);
+ selection.add(ids[1]);
+ selection.add(ids[2]);
}
public void testAdd() {
// We added in setUp.
assertEquals(3, selection.size());
- assertContains(3);
- assertContains(5);
- assertContains(9);
+ assertContains(ids[0]);
+ assertContains(ids[1]);
+ assertContains(ids[2]);
}
public void testRemove() {
- selection.remove(3);
- selection.remove(5);
+ selection.remove(ids[0]);
+ selection.remove(ids[2]);
assertEquals(1, selection.size());
- assertContains(9);
+ assertContains(ids[1]);
}
public void testClear() {
@@ -60,10 +70,10 @@
assertTrue(selection.isEmpty());
}
- public void testSizeAndGet() {
+ public void testSize() {
Selection other = new Selection();
for (int i = 0; i < selection.size(); i++) {
- other.add(selection.get(i));
+ other.add(ids[i]);
}
assertEquals(selection.size(), other.size());
}
@@ -74,9 +84,9 @@
public void testEqualsOther() {
Selection other = new Selection();
- other.add(3);
- other.add(5);
- other.add(9);
+ other.add(ids[0]);
+ other.add(ids[1]);
+ other.add(ids[2]);
assertEquals(selection, other);
assertEquals(selection.hashCode(), other.hashCode());
}
@@ -90,65 +100,78 @@
public void testNotEquals() {
Selection other = new Selection();
- other.add(789);
+ other.add("foobar");
assertFalse(selection.equals(other));
}
- public void testExpandBefore() {
- selection.expand(2, 10);
- assertEquals(3, selection.size());
- assertContains(13);
- assertContains(15);
- assertContains(19);
+ public void testIntersection_empty0() {
+ Selection testSelection = new Selection();
+ testSelection.intersect(new HashSet<String>());
+ assertTrue(testSelection.isEmpty());
}
- public void testExpandAfter() {
- selection.expand(10, 10);
- assertEquals(3, selection.size());
- assertContains(3);
- assertContains(5);
- assertContains(9);
+ public void testIntersection_empty1() {
+ Selection testSelection = new Selection();
+ testSelection.intersect(Sets.newHashSet("foo"));
+ assertTrue(testSelection.isEmpty());
}
- public void testExpandSplit() {
- selection.expand(5, 10);
- assertEquals(3, selection.size());
- assertContains(3);
- assertContains(15);
- assertContains(19);
+ public void testIntersection_empty2() {
+ assertFalse(selection.isEmpty());
+ selection.intersect(new HashSet<String>());
+ assertTrue(selection.isEmpty());
}
- public void testExpandEncompased() {
- selection.expand(2, 10);
- assertEquals(3, selection.size());
- assertContains(13);
- assertContains(15);
- assertContains(19);
+ public void testIntersection_exclusive() {
+ String[] ids0 = new String[]{"foo", "bar", "baz"};
+ String[] ids1 = new String[]{"0", "1", "2"};
+
+ Selection testSelection = new Selection();
+ testSelection.add(ids0[0]);
+ testSelection.add(ids0[1]);
+ testSelection.add(ids0[2]);
+
+ Set<String> set = Sets.newHashSet(ids1);
+ testSelection.intersect(set);
+
+ assertTrue(testSelection.isEmpty());
}
- public void testCollapseBefore() {
- selection.collapse(0, 2);
- assertEquals(3, selection.size());
- assertContains(1);
- assertContains(3);
- assertContains(7);
+ public void testIntersection_subset() {
+ String[] ids0 = new String[]{"foo", "bar", "baz"};
+ String[] ids1 = new String[]{"0", "baz", "1", "foo", "2"};
+
+ Selection testSelection = new Selection();
+ testSelection.add(ids0[0]);
+ testSelection.add(ids0[1]);
+ testSelection.add(ids0[2]);
+
+ testSelection.intersect(Sets.newHashSet(ids1));
+
+ assertTrue(testSelection.contains("foo"));
+ assertFalse(testSelection.contains("bar"));
+ assertTrue(testSelection.contains("baz"));
}
- public void testCollapseAfter() {
- selection.collapse(10, 10);
- assertEquals(3, selection.size());
- assertContains(3);
- assertContains(5);
- assertContains(9);
+ public void testIntersection_all() {
+ String[] ids0 = new String[]{"foo", "bar", "baz"};
+ String[] ids1 = new String[]{"0", "baz", "1", "foo", "2", "bar"};
+
+ Selection testSelection = new Selection();
+ testSelection.add(ids0[0]);
+ testSelection.add(ids0[1]);
+ testSelection.add(ids0[2]);
+
+ Selection control = new Selection();
+ control.copyFrom(testSelection);
+
+ testSelection.intersect(Sets.newHashSet(ids1));
+
+ assertTrue(testSelection.equals(control));
}
- public void testCollapseAcross() {
- selection.collapse(0, 10);
- assertEquals(0, selection.size());
- }
-
- private void assertContains(int i) {
- String err = String.format("Selection %s does not contain %d", selection, i);
- assertTrue(err, selection.contains(i));
+ private void assertContains(String id) {
+ String err = String.format("Selection %s does not contain %s", selection, id);
+ assertTrue(err, selection.contains(id));
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
new file mode 100644
index 0000000..c8d424f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.test.mock.MockContentProvider;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A very simple test double for ContentProvider. Useful in this package only.
+ */
+class TestContentProvider extends MockContentProvider {
+ List<Uri> mDeleted = new ArrayList<>();
+
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ // Intercept and log delete method calls.
+ if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
+ final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+ mDeleted.add(documentUri);
+ return new Bundle();
+ } else {
+ return super.call(method, arg, extras);
+ }
+ }
+
+ public void assertWasDeleted(DocumentInfo doc) {
+ ModelTest.assertTrue(mDeleted.contains(doc.derivedUri));
+ }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
new file mode 100644
index 0000000..714062d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.test.mock.MockContentResolver;
+
+public final class TestContext {
+
+ /**
+ * Returns a Context configured with test provider for authority.
+ */
+ static Context createStorageTestContext(Context context, String authority) {
+ final MockContentResolver testResolver = new MockContentResolver();
+ TestContentProvider provider = new TestContentProvider();
+ testResolver.addProvider(authority, provider);
+
+ return new ContextWrapper(context) {
+ @Override
+ public ContentResolver getContentResolver() {
+ return testResolver;
+ }
+ };
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
new file mode 100644
index 0000000..267f47d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A skeletal {@link DocumentsAdapter} test double.
+ */
+public class TestDocumentsAdapter extends DocumentsAdapter {
+
+ List<String> mModelIds = new ArrayList<>();
+
+ public TestDocumentsAdapter(List<String> modelIds) {
+ mModelIds = modelIds;
+ }
+
+ @Override
+ public void onModelUpdate(Model model) {
+ }
+
+ @Override
+ public void onModelUpdateFailed(Exception e) {
+ }
+
+ @Override
+ List<String> getModelIds() {
+ return mModelIds;
+ }
+
+ @Override
+ void onItemSelectionChanged(String id) {
+ }
+
+ @Override
+ String getModelId(int position) {
+ return mModelIds.get(position);
+ }
+
+ @Override
+ public SparseArray<String> hide(String... ids) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ void unhide(SparseArray<String> ids) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void onBindViewHolder(DocumentHolder holder, int position) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mModelIds.size();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
new file mode 100644
index 0000000..3a537a6
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
+import java.util.Random;
+import java.util.Set;
+
+public class TestModel extends Model {
+
+ private static final String[] COLUMNS = new String[]{
+ RootCursorWrapper.COLUMN_AUTHORITY,
+ Document.COLUMN_DOCUMENT_ID,
+ Document.COLUMN_FLAGS,
+ Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_SIZE,
+ Document.COLUMN_MIME_TYPE
+ };
+
+ private final String mAuthority;
+ private Set<String> mDeleted;
+
+ /**
+ * Creates a new context. context must be configured with provider for authority.
+ * @see TestContext#createStorageTestContext(Context, String).
+ */
+ public TestModel(Context context, String authority) {
+ super(context);
+ mAuthority = authority;
+ }
+
+ void update(String... names) {
+ Random rand = new Random();
+
+ MatrixCursor c = new MatrixCursor(COLUMNS);
+ for (int i = 0; i < names.length; i++) {
+ MatrixCursor.RowBuilder row = c.newRow();
+ row.add(RootCursorWrapper.COLUMN_AUTHORITY, mAuthority);
+ row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+ row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+ // Generate random document names and sizes. This forces the model's internal sort code
+ // to actually do something.
+ row.add(Document.COLUMN_DISPLAY_NAME, names[i]);
+ row.add(Document.COLUMN_SIZE, rand.nextInt());
+ }
+
+ DirectoryResult r = new DirectoryResult();
+ r.cursor = c;
+ update(r);
+ }
+
+ // Note that model id includes authority qualifier and is distinct
+ // WRT documentId because of this.
+ String idForPosition(int p) {
+ return createModelId(mAuthority, Integer.toString(p));
+ }
+
+ @Override
+ public void delete(Selection selected, DeletionListener listener) {
+ for (String id : selected.getAll()) {
+ mDeleted.add(id);
+ }
+ listener.onCompletion();
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
index b4324a8..c4cfd3a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -23,8 +23,13 @@
import com.android.documentsui.dirlist.MultiSelectManager.SelectionEnvironment;
+import java.util.List;
+
public class TestSelectionEnvironment implements SelectionEnvironment {
+ public TestSelectionEnvironment(List<String> items) {
+ }
+
@Override
public void showBand(Rect rect) {
}
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index db825ff4..ec6af2f 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,6 +5,7 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
LOCAL_PACKAGE_NAME := ExternalStorageProvider
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..b280d4f
--- /dev/null
+++ b/packages/ExternalStorageProvider/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <string name="app_label" msgid="7123375275748530234">"Spoljna memorija"</string>
+ <string name="root_internal_storage" msgid="827844243068584127">"Interna memorija"</string>
+ <string name="root_home" msgid="7931555396767513359">"Početni"</string>
+</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 2cedc72..c6e5531 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -39,6 +39,7 @@
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
+import android.support.provider.DocumentArchiveHelper;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.DebugUtils;
@@ -93,6 +94,7 @@
private StorageManager mStorageManager;
private Handler mHandler;
+ private DocumentArchiveHelper mArchiveHelper;
private final Object mRootsLock = new Object();
@@ -106,6 +108,7 @@
public boolean onCreate() {
mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE);
mHandler = new Handler();
+ mArchiveHelper = new DocumentArchiveHelper(this, (char) 0);
updateVolumes();
return true;
@@ -321,8 +324,12 @@
}
}
- final String displayName = file.getName();
final String mimeType = getTypeForFile(file);
+ if (mArchiveHelper.isSupportedArchiveType(mimeType)) {
+ flags |= Document.FLAG_ARCHIVE;
+ }
+
+ final String displayName = file.getName();
if (mimeType.startsWith("image/")) {
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
}
@@ -333,6 +340,7 @@
row.add(Document.COLUMN_SIZE, file.length());
row.add(Document.COLUMN_MIME_TYPE, mimeType);
row.add(Document.COLUMN_FLAGS, flags);
+ row.add(DocumentArchiveHelper.COLUMN_LOCAL_FILE_PATH, file.getPath());
// Only publish dates reasonably after epoch
long lastModified = file.lastModified();
@@ -361,6 +369,10 @@
@Override
public boolean isChildDocument(String parentDocId, String docId) {
try {
+ if (mArchiveHelper.isArchivedDocument(docId)) {
+ return mArchiveHelper.isChildDocument(parentDocId, docId);
+ }
+
final File parent = getFileForDocId(parentDocId).getCanonicalFile();
final File doc = getFileForDocId(docId).getCanonicalFile();
return FileUtils.contains(parent, doc);
@@ -468,6 +480,10 @@
@Override
public Cursor queryDocument(String documentId, String[] projection)
throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(documentId)) {
+ return mArchiveHelper.queryDocument(documentId, projection);
+ }
+
final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection));
includeFile(result, documentId, null);
return result;
@@ -477,6 +493,11 @@
public Cursor queryChildDocuments(
String parentDocumentId, String[] projection, String sortOrder)
throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(parentDocumentId) ||
+ mArchiveHelper.isSupportedArchiveType(getDocumentType(parentDocumentId))) {
+ return mArchiveHelper.queryChildDocuments(parentDocumentId, projection, sortOrder);
+ }
+
final File parent = getFileForDocId(parentDocumentId);
final MatrixCursor result = new DirectoryCursor(
resolveDocumentProjection(projection), parentDocumentId, parent);
@@ -514,6 +535,10 @@
@Override
public String getDocumentType(String documentId) throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(documentId)) {
+ return mArchiveHelper.getDocumentType(documentId);
+ }
+
final File file = getFileForDocId(documentId);
return getTypeForFile(file);
}
@@ -522,6 +547,10 @@
public ParcelFileDescriptor openDocument(
String documentId, String mode, CancellationSignal signal)
throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(documentId)) {
+ return mArchiveHelper.openDocument(documentId, mode, signal);
+ }
+
final File file = getFileForDocId(documentId);
final File visibleFile = getFileForDocId(documentId, true);
@@ -550,6 +579,10 @@
public AssetFileDescriptor openDocumentThumbnail(
String documentId, Point sizeHint, CancellationSignal signal)
throws FileNotFoundException {
+ if (mArchiveHelper.isArchivedDocument(documentId)) {
+ return mArchiveHelper.openDocumentThumbnail(documentId, sizeHint, signal);
+ }
+
final File file = getFileForDocId(documentId);
return DocumentsContract.openImageThumbnail(file);
}
diff --git a/packages/FusedLocation/res/values-b+sr+Latn/strings.xml b/packages/FusedLocation/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..0d2cccc
--- /dev/null
+++ b/packages/FusedLocation/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="5379477904423203699">"Fused Location"</string>
+</resources>
diff --git a/packages/InputDevices/res/values-b+sr+Latn/strings.xml b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..88a977f
--- /dev/null
+++ b/packages/InputDevices/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_label" msgid="8016145283189546017">"Ulazni uređaji"</string>
+ <string name="keyboard_layouts_label" msgid="6688773268302087545">"Android tastatura"</string>
+ <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"engleska (UK)"</string>
+ <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"engleska (SAD)"</string>
+ <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"engleska (SAD), međunarodni stil"</string>
+ <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"engleska (SAD), Colemak stil"</string>
+ <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"engleska (SAD), Dvorak stil"</string>
+ <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"engleska (SAD), Workman stil"</string>
+ <string name="keyboard_layout_german_label" msgid="8451565865467909999">"nemačka"</string>
+ <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuska"</string>
+ <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuska (Kanada)"</string>
+ <string name="keyboard_layout_russian_label" msgid="8724879775815042968">"ruska"</string>
+ <string name="keyboard_layout_russian_mac_label" msgid="3795866869038264796">"ruska, Mac stil"</string>
+ <string name="keyboard_layout_spanish_label" msgid="7091555148131908240">"španska"</string>
+ <string name="keyboard_layout_swiss_french_label" msgid="4659191025396371684">"švajcarsko francuska"</string>
+ <string name="keyboard_layout_swiss_german_label" msgid="2305520941993314258">"švajcarsko nemačka"</string>
+ <string name="keyboard_layout_belgian" msgid="2011984572838651558">"belgijska"</string>
+ <string name="keyboard_layout_bulgarian" msgid="8951224309972028398">"bugarska"</string>
+ <string name="keyboard_layout_italian" msgid="6497079660449781213">"italijanska"</string>
+ <string name="keyboard_layout_danish" msgid="8036432066627127851">"danska"</string>
+ <string name="keyboard_layout_norwegian" msgid="9090097917011040937">"norveška"</string>
+ <string name="keyboard_layout_swedish" msgid="732959109088479351">"švedska"</string>
+ <string name="keyboard_layout_finnish" msgid="5585659438924315466">"finska"</string>
+ <string name="keyboard_layout_croatian" msgid="4172229471079281138">"hrvatska"</string>
+ <string name="keyboard_layout_czech" msgid="1349256901452975343">"češka"</string>
+ <string name="keyboard_layout_estonian" msgid="8775830985185665274">"estonska"</string>
+ <string name="keyboard_layout_hungarian" msgid="4154963661406035109">"mađarska"</string>
+ <string name="keyboard_layout_icelandic" msgid="5836645650912489642">"islandska"</string>
+ <string name="keyboard_layout_brazilian" msgid="5117896443147781939">"brazilska"</string>
+ <string name="keyboard_layout_portuguese" msgid="2888198587329660305">"portugalska"</string>
+ <string name="keyboard_layout_slovak" msgid="2469379934672837296">"slovačka"</string>
+ <string name="keyboard_layout_slovenian" msgid="1735933028924982368">"slovenačka"</string>
+ <string name="keyboard_layout_turkish" msgid="7736163250907964898">"turska"</string>
+ <string name="keyboard_layout_ukrainian" msgid="8176637744389480417">"ukrajinska"</string>
+ <string name="keyboard_layout_arabic" msgid="5671970465174968712">"arapski"</string>
+ <string name="keyboard_layout_greek" msgid="7289253560162386040">"grčki"</string>
+ <string name="keyboard_layout_hebrew" msgid="7241473985890173812">"hebrejski"</string>
+ <string name="keyboard_layout_lithuanian" msgid="6943110873053106534">"litvanski"</string>
+ <string name="keyboard_layout_spanish_latin" msgid="5690539836069535697">"španski (Latinska Amerika)"</string>
+ <string name="keyboard_layout_latvian" msgid="4405417142306250595">"letonski"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index efff2a8..428c842 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Voer weer die korrekte PUK-kode in. Herhaalde pogings sal die SIM permanent deaktiveer."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodes stem nie ooreen nie"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogings"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jy het jou PIN <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd ingetik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%d</xliff:g> keer jou wagwoord verkeerdelik getik. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. \n\nProbeer weer oor <xliff:g id="NUMBER_1">%d</xliff:g> sekondes."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%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="1843331751334128428">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal hierdie foon teruggestel word, wat al sy data sal uitvee."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"Jy het <xliff:g id="NUMBER_0">%1$d</xliff:g> keer jou wagwoord verkeerdelik getik. \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="74089475965050805">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik 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="8774056606869646621">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <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="1843331751334128428">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%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="6945823186629369880">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <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="6945823186629369880">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <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_now_erasing_user" product="tablet" msgid="3963486905355778734">"Jy het die tablet <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie gebruiker sal verwyder word, wat alle gebruikerdata sal uitvee."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Jy het die foon <xliff:g id="NUMBER">%d</xliff:g> keer verkeerd probeer ontsluit. Hierdie gebruiker sal verwyder word, wat alle gebruikerdata sal uitvee."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jy het die tablet <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jy het die foon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jy het die tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jy het die foon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerd probeer ontsluit. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings sal die werkprofiel verwyder word, wat alle profieldata sal uitvee."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening.\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="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\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="30531039455764924">"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="6721575017538162249">
<item quantity="other">Verkeerde SIM-PIN-kode. Jy het <xliff:g id="NUMBER_1">%d</xliff:g> pogings oor.</item>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 24f87ed..e0520b1 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ትክክለኛውን የPUK ኮድ እንደገና ያስገቡ። ተደጋጋሚ ሙከራዎች ሲም ካርዱን እስከመጨረሻው ያሰናክሉታል።"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ፒን ኮዶች አይገጣጠሙም"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"በጣም ብዙ የስርዓተ ጥለት ሙከራዎች"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልተየቡም። \n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"የይለፍ ቃልዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መንገድ ተይበዋል።\n\nበ<xliff:g id="NUMBER_1">%d</xliff:g> ሰኮንዶች ውስጥ እንደገና ይሞክሩ።"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"የመክፈቻ ስርዓተ ጥለትዎን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። \n\n ከ<xliff:g id="NUMBER_1">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ጡባዊውን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ስልክ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ፒንዎን <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="7813713389422226531">"የይለፍ ቃልዎን <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="74089475965050805">"የመክፈቻ ስርዓተ ጥለትዎን <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="8774056606869646621">"ጡባዊውን <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="1843331751334128428">"ስልኩን <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="258925501999698032">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ ሁኔታ ለማስከፈት ሞክረዋል። ስልኩ ዳግም ይጀመራል፣ ይህም ሁሉንም ውሂቡን ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ጡባዊውን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ጡባዊውን <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="6945823186629369880">"ስልኩን <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_erasing_user" product="tablet" msgid="3963486905355778734">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ይህ ተጠቃሚ ይወገዳል፣ ይህም ሁሉንም የተጠቃሚ ውሂብ ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ጡባዊውን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ስልኩን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ጡባዊውን <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_profile" product="default" msgid="6853071165802933545">"ስልኩን <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ጡባዊውን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ስልኩን <xliff:g id="NUMBER">%d</xliff:g> ጊዜ ትክክል ባልሆነ መልኩ ለማስከፈት ሞክረዋል። የስራ መገለጫው ይወገዳል፣ ይህም ሁሉንም የመገለጫ ውሂብ ይሰርዛል።"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ጡባዊ ቱኮዎን እንዲከፍቱ ይጠየቃሉ።\n\n ከ<xliff:g id="NUMBER_2">%d</xliff:g> ከሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"የመክፈቻ ስርዓተ ጥለቱን <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="1437638152015574839">"የመክፈቻ ስርዓተ ጥለቱን <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="30531039455764924">"ልክ ያልሆነ የሲም ኮድ። አሁን መሳሪያዎን ለማስከፈት ድምጸ ተያያዥ ሞደምዎን ማግኘት አለብዎ።"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">ልክ ያልሆነ የሲም ፒን ኮድ፣ <xliff:g id="NUMBER_1">%d</xliff:g> ሙከራዎች ይቀርዎታል።</item>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index b326238..c2db559 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"أعد إدخال رمز PUK الصحيح. وستؤدي المحاولات المتكررة إلى تعطيل شريحة SIM نهائيًا."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"لا يتطابق رمزا رمز PIN"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"محاولات النقش كثيرة جدًا"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رمز PIN بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"لقد كتبت كلمة المرور بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <xliff:g id="NUMBER_0">%d</xliff:g> مرة. \n\nأعد المحاولة خلال <xliff:g id="NUMBER_1">%d</xliff:g> ثانية."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين هذا الجهاز والتي بدورها تحذف جميع بياناته."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إعادة تعيين هذا الهاتف والتي بدورها تحذف جميع بياناته."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"لقد كتبت رمز 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="7813713389422226531">"لقد كتبت كلمة المرور بشكل غير صحيح <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="74089475965050805">"لقد رسمت نقش إلغاء التأمين بطريقة غير صحيحة <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="8774056606869646621">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <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="1843331751334128428">"أخطأت في محاولة إلغاء قفل الهاتف <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="258925501999698032">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إعادة تعيين هذا الجهاز والتي بدورها تحذف جميع بياناته."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إعادة تعيين هذا الهاتف والتي بدورها تحذف جميع بياناته."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة هذا المستخدم والتي بدورها تحذف جميع بيانات المستخدم."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة هذا المستخدم والتي بدورها تحذف جميع بيانات المستخدم."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <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="6945823186629369880">"أخطأت في محاولة إلغاء قفل الهاتف <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_erasing_user" product="tablet" msgid="3963486905355778734">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة المستخدم والتي بدورها تحذف جميع بياناته."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة المستخدم والتي بدورها تحذف جميع بياناته."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بيانات الملف الشخصي."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER_0">%d</xliff:g> من المرات. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بيانات الملف الشخصي."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <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_profile" product="default" msgid="6853071165802933545">"أخطأت في محاولة إلغاء قفل الهاتف <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_erasing_profile" product="tablet" msgid="4686386497449912146">"أخطأت في محاولة إلغاء قفل الجهاز اللوحي <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بياناته."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"أخطأت في محاولة إلغاء قفل الهاتف <xliff:g id="NUMBER">%d</xliff:g> من المرات. ستتم إزالة الملف الشخصي للعمل والتي بدورها تحذف جميع بياناته."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <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="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <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="30531039455764924">"رمز \"رقم التعريف الشخصي\" لبطاقة SIM غير صحيح، ويلزمك الاتصال الآن بمشغّل شبكة الجوّال لإلغاء قفل الجهاز."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="zero">رمز رقم التعريف الشخصي لبطاقة SIM غير صحيح، ولم تتبق لديك أية محاولات (<xliff:g id="NUMBER_1">%d</xliff:g>).</item>
diff --git a/packages/Keyguard/res/values-az-rAZ/strings.xml b/packages/Keyguard/res/values-az-rAZ/strings.xml
index 6e336be..575d035 100644
--- a/packages/Keyguard/res/values-az-rAZ/strings.xml
+++ b/packages/Keyguard/res/values-az-rAZ/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Düzgün PUK kodu yenidən 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="7003469261464593516">"PIN kodları uyğun deyil"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Həddindən çox cəhd edildi!"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etdiniz.\n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrənizi <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etdiniz. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Modelinizi <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış çəkmisiniz.\n\n <xliff:g id="NUMBER_1">%d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <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ə ərzində yenidən yoxlayın"</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrənizi <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ə ərzində yenidən yoxlayın."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Modelinizi <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış çəkmisiniz.\n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> saniyə ərzində yenidən yoxlayın"</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu planşet ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu telefon ilkin vəziyyətinə bərpa olunacaq və ondakı bütün məlumatlar silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Daha <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün istifadəçi məlumatlarını siləcək bu istifadəçi silinəcəkdir."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu istifadəçi və istifadəçi ilə bağlı bütün məlumatlar silinəcəkdir."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bu istifadəçi və istifadəçi ilə bağlı bütün məlumatlar silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz <xliff:g id="NUMBER_0">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> uğursuz cəhddən sonra bütün profil məlumatlarını siləcək iş profili silinəcəkdir."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə planşetinizin kilidini açmaq üçün yanlış cəhdlər etdiniz. Bütün profil məlumatlarınızı siləcək iş profili silinəcəkdir."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Siz <xliff:g id="NUMBER">%d</xliff:g> dəfə telefonunuzun kilidini açmaq üçün yanlış cəhdlər etdiniz. Bütün profil məlumatlarınızı siləcək iş profili silinəcəkdir."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz kilidi açmaq üçün şablonu <xliff:g id="NUMBER_0">%d</xliff:g> dəfə səhv çəkdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> daha uğursuz cəhddən sonra planşetinizin kilidini e-poçt hesabınızla açmaq tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniyə ərzində bir daha yoxlayın."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz artıq modeli <xliff:g id="NUMBER_0">%d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniyə ərzində yenidən cəhd edin."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz kilidi açmaq üçün şablonu <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə səhv çəkdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> daha uğursuz cəhddən sonra planşetinizin 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ə ərzində bir daha yoxlayın."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz artıq modeli <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%2$d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində yenidən cəhd edin."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Yanlış SIM PIN kodu cihazınızın açılması üçün operatorunuzla indi əlaqə saxlamalısınız."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Yanlış SIM PIN kodu, <xliff:g id="NUMBER_1">%d</xliff:g> cəhdiniz qalır.</item>
diff --git a/packages/Keyguard/res/values-b+sr+Latn/strings.xml b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..8b6ba5d
--- /dev/null
+++ b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+ <string name="app_name" msgid="719438068451601849">"Zaštita tastera"</string>
+ <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN kôd"</string>
+ <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"Unesite SIM PUK kôd i novi PIN kôd"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK kôd"</string>
+ <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"Novi SIM PIN kôd"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite da biste uneli lozinku"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Otkucajte lozinku da biste otključali"</string>
+ <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje"</string>
+ <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kôd je netačan."</string>
+ <string name="keyguard_charged" msgid="3272223906073492454">"Napunjeno"</string>
+ <string name="keyguard_plugged_in" msgid="9087497435553252863">"Punjenje"</string>
+ <string name="keyguard_plugged_in_charging_fast" msgid="6671162730167305479">"Brzo se puni"</string>
+ <string name="keyguard_plugged_in_charging_slowly" msgid="1964714661071163229">"Sporo se puni"</string>
+ <string name="keyguard_low_battery" msgid="8143808018719173859">"Povežite punjač."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"Pritisnite Meni da biste otključali."</string>
+ <string name="keyguard_network_locked_message" msgid="9169717779058037168">"Mreža je zaključana"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"Nema SIM kartice"</string>
+ <string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"U tabletu nema SIM kartice."</string>
+ <string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"U telefonu nema SIM kartice."</string>
+ <string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"Umetnite SIM karticu."</string>
+ <string name="keyguard_missing_sim_instructions_long" msgid="5968985489463870358">"SIM kartica nedostaje ili ne može da se pročita. Umetnite SIM karticu."</string>
+ <string name="keyguard_permanent_disabled_sim_message_short" msgid="8340813989586622356">"SIM kartica je neupotrebljiva."</string>
+ <string name="keyguard_permanent_disabled_sim_instructions" msgid="5892940909699723544">"SIM kartica je trajno onemogućena.\n Obratite se dobavljaču usluge bežične mreže da biste dobili drugu SIM karticu."</string>
+ <string name="keyguard_sim_locked_message" msgid="6875773413306380902">"SIM kartica je zaključana."</string>
+ <string name="keyguard_sim_puk_locked_message" msgid="3747232467471801633">"SIM kartica je zaključana PUK kodom."</string>
+ <string name="keyguard_sim_unlock_progress_dialog_message" msgid="7975221805033614426">"Otključavanje SIM kartice…"</string>
+ <string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"Otključavanje šablonom."</string>
+ <string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje PIN-om."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
+ <string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Oblast šablona."</string>
+ <string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast prevlačenja."</string>
+ <string name="keyguard_accessibility_pin_area" msgid="7903959476607833485">"Oblast za PIN"</string>
+ <string name="keyguard_accessibility_sim_pin_area" msgid="3887780775111719336">"Oblast za PIN za SIM"</string>
+ <string name="keyguard_accessibility_sim_puk_area" msgid="1880823406954996207">"Oblast za PUK za SIM"</string>
+ <string name="keyguard_accessibility_next_alarm" msgid="7269583073750518672">"Sledeći alarm je podešen za <xliff:g id="ALARM">%1$s</xliff:g>"</string>
+ <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
+ <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Zaboravljeni šablon"</string>
+ <string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
+ <string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
+ <string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
+ <string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Unesite PIN za SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"Unesite lozinku"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"SIM kartica je sada onemogućena. Unesite PUK kôd da biste nastavili. Za detalje kontaktirajte operatera."</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="363822494559783025">"SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“ je sada onemogućen. Unesite PUK kôd da biste nastavili. Kontaktirajte operatera za detalje."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"Unesite željeni PIN kôd"</string>
+ <string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"Potvrdite željeni PIN kôd"</string>
+ <string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"Otključavanje SIM kartice…"</string>
+ <string name="kg_invalid_sim_pin_hint" msgid="8795159358110620001">"Unesite PIN koji ima od 4 do 8 brojeva."</string>
+ <string name="kg_invalid_sim_puk_hint" msgid="7553388325654369575">"PUK kôd treba da ima 8 ili više brojeva."</string>
+ <string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravni PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
+ <string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi se ne podudaraju"</string>
+ <string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja unosa šablona"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni 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> sekunde(i)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu 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> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se tablet resetuje i svi podaci sa njega brišu."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se telefon resetuje i svi podaci sa njega brišu."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Tablet će biti resetovan i svi podaci sa njega će biti izbrisani."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Telefon će biti resetovan i svi podaci sa njega će biti izbrisani."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se ovaj korisnik uklanja i svi podaci korisnika brišu."</string>
+ <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Ovaj korisnik će biti uklonjen i svi podaci korisnika će biti izbrisani."</string>
+ <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Ovaj korisnik će biti uklonjen i svi podaci korisnika će biti izbrisani."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
+ <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netačan SIM PIN kôd. Sada morate da kontaktirate mobilnog operatera da biste otključali uređaj."</string>
+ <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
+ <item quantity="one">Netačan SIM PIN kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
+ <item quantity="few">Netačan SIM PIN kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ <item quantity="other">Netačan SIM PIN kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja.</item>
+ </plurals>
+ <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM kartica je neupotrebljiva. Kontaktirajte mobilnog operatera."</string>
+ <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
+ <item quantity="one">Netačan SIM PUK kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj pre nego što SIM kartica postane trajno neupotrebljiva.</item>
+ <item quantity="few">Netačan SIM PUK kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM kartica postane trajno neupotrebljiva.</item>
+ <item quantity="other">Netačan SIM PUK kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM kartica postane trajno neupotrebljiva.</item>
+ </plurals>
+ <string name="kg_password_pin_failed" msgid="6268288093558031564">"Radnja sa SIM PIN kodom nije uspela!"</string>
+ <string name="kg_password_puk_failed" msgid="2838824369502455984">"Radnja sa SIM PUK kodom nije uspela!"</string>
+ <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
+ <string name="keyguard_carrier_default" msgid="8700650403054042153">"Oflajn ste."</string>
+ <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Dugme Promeni metod unosa."</string>
+ <string name="airplane_mode" msgid="3122107900897202805">"Režim rada u avionu"</string>
+ <string name="kg_prompt_reason_restart_pattern" msgid="489430505491862444">"Šablon je obavezan kada ponovo pokrećete uređaj."</string>
+ <string name="kg_prompt_reason_restart_pin" msgid="994878216570694974">"PIN je obavezan kada ponovo pokrećete uređaj."</string>
+ <string name="kg_prompt_reason_restart_password" msgid="2375742919528461664">"Lozinka je obavezna kada ponovo pokrećete uređaj."</string>
+ <string name="kg_prompt_reason_timeout_pattern" msgid="8930047492617900785">"Potreban je šablon radi dodatne bezbednosti."</string>
+ <string name="kg_prompt_reason_timeout_pin" msgid="7470468607947726377">"Potreban je PIN radi dodatne bezbednosti."</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="1177412542773936957">"Potrebna je lozinka radi dodatne bezbednosti."</string>
+ <string name="kg_prompt_reason_switch_profiles_pattern" msgid="3802056699323773969">"Šablon je obavezan kada prelazite sa jednog profila na drugi."</string>
+ <string name="kg_prompt_reason_switch_profiles_pin" msgid="8108020184731052246">"PIN je obavezan kada prelazite sa jednog profila na drugi."</string>
+ <string name="kg_prompt_reason_switch_profiles_password" msgid="6755997057852042672">"Lozinka je obavezna kada prelazite sa jednog profila na drugi."</string>
+ <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
+ <item quantity="one">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite šablon.</item>
+ <item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite šablon.</item>
+ <item quantity="other">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite šablon.</item>
+ </plurals>
+ <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
+ <item quantity="one">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite PIN.</item>
+ <item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite PIN.</item>
+ <item quantity="other">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite PIN.</item>
+ </plurals>
+ <plurals name="kg_prompt_reason_time_password" formatted="false" msgid="5132693663364913675">
+ <item quantity="one">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite lozinku.</item>
+ <item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite lozinku.</item>
+ <item quantity="other">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sati. Potvrdite lozinku.</item>
+ </plurals>
+ <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nije prepoznat"</string>
+</resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index 7fbf46a..2c42dc0 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Въведете отново правилния PUK код. Многократните опити ще деактивират за постоянно SIM картата."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовете не съвпадат"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Опитите за фигурата са твърде много"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Въведохте неправилно паролата си <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. \n\nОпитайте отново след <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Въведохте неправилно ПИН кода си <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="7813713389422226531">"Въведохте неправилно паролата си <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="74089475965050805">"Начертахте неправилно фигурата си за отключване <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="8774056606869646621">"Неправилно опитахте да отключите таблета <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="1843331751334128428">"Неправилно опитахте да отключите телефона <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="258925501999698032">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Той ще бъде нулиран, при което ще се изтрият всичките му данни."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Неправилно опитахте да отключите таблета <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="6945823186629369880">"Неправилно опитахте да отключите телефона <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_erasing_user" product="tablet" msgid="3963486905355778734">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER">%d</xliff:g> пъти. Този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Този потребител ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Неправилно опитахте да отключите таблета <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_profile" product="default" msgid="6853071165802933545">"Неправилно опитахте да отключите телефона <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Неправилно опитахте да отключите таблета <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно опитахте да отключите телефона <xliff:g id="NUMBER">%d</xliff:g> пъти. Служебният потребителски профил ще бъде премахнат, при което ще се изтрият всички данни за него."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <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="1437638152015574839">"Начертахте неправилно фигурата си за отключване <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="30531039455764924">"Неправилен ПИН код за SIM картата – сега трябва да се свържете с оператора си, за да отключите устройството."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Неправилен ПИН код за SIM картата – остават ви <xliff:g id="NUMBER_1">%d</xliff:g> опита.</item>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 83ca30e..bec579c 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"সঠিক PUK কোড পুনরায় লিখুন৷ বার বার প্রচেষ্টা করা হলে তা স্থায়ীভাবে সিমটিকে অক্ষম করে দেবে৷"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"পিন কোডগুলি মিলছে না"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"বিভিন্ন প্যাটার্নের সাহায্যে খুব বেশি বার প্রচেষ্টা করা হয়ে গেছে"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপনি আপনার পাসওয়ার্ড <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল টাইপ করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"আপনি আপনার পাসওয়ার্ড <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল টাইপ করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ট্যাবলেটটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ফোনটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"আপনি আপনার পাসওয়ার্ড <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="7813713389422226531">"আপনি আপনার পাসওয়ার্ড <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="74089475965050805">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <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="8774056606869646621">"আপনি <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="1843331751334128428">"আপনি <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="258925501999698032">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ এই ট্যাবলেটটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ এই ফোনটিকে পুনরায় সেট করা হবে যা এটির সমস্ত ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"আপনি <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="6945823186629369880">"আপনি <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_erasing_user" product="tablet" msgid="3963486905355778734">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন৷ এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ফোনটি আনলক করার চেষ্টা করেছেন৷ এই ব্যবহারকারীকে সরানো হবে যা সমস্ত ব্যবহারকারীর ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ট্যাবলেট আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"আপনি <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করে ফোন আনলক করার চেষ্টা করেছেন৷ <xliff:g id="NUMBER_1">%d</xliff:g>টি অসফল প্রচেষ্টার পরে, কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"আপনি <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_profile" product="default" msgid="6853071165802933545">"আপনি <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_erasing_profile" product="tablet" msgid="4686386497449912146">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ট্যাবলেটটি আনলক করার চেষ্টা করেছেন৷ কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"আপনি <xliff:g id="NUMBER">%d</xliff:g> বার ভুল করে ফোনটি আনলক করার চেষ্টা করেছেন৷ কাজের প্রোফাইল সরানো হবে যা সমস্ত প্রোফাইল ডেটা মুছে ফেলবে৷"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ট্যাবলেট আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <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="1437638152015574839">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <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="30531039455764924">"ভুল সিম পিন কোড, আপনার ডিভাইসটি আনলক করতে এখন আপনাকে অবশ্যই আপনার ক্যারিয়ারের সাথে যোগাযোগ করতে হবে৷"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">ভুল SIM পিন কোড, আপনার কাছে আর <xliff:g id="NUMBER_1">%d</xliff:g>টি প্রচেষ্টা বাকি রয়েছে৷</item>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 42ae52e..30d9289 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM de manera permanent."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Els codis PIN no coincideixen"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Massa intents incorrectes"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> vegades. \n\nTorna-ho a provar d\'aquí a <xliff:g id="NUMBER_1">%d</xliff:g> segons."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, la tauleta es restablirà i se n\'esborraran totes les dades."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el telèfon es restablirà i se n\'esborraran totes les dades."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has escrit malament el PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \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="7813713389422226531">"Has escrit malament la contrasenya <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \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="74089475965050805">"Has dibuixat el patró de desbloqueig de manera incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. \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="8774056606869646621">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, la tauleta es restablirà i se n\'esborraran totes les dades."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el telèfon es restablirà i se n\'esborraran totes les dades."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. La tauleta es restablirà i se n\'esborraran totes les dades."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El telèfon es restablirà i se n\'esborraran totes les dades."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, l\'usuari se suprimirà, juntament amb totes les seves dades."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. L\'usuari se suprimirà, juntament amb totes les seves dades."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. L\'usuari se suprimirà, juntament amb totes les seves dades."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades. Et queden <xliff:g id="NUMBER_1">%2$d</xliff:g> intents més. Si no ho fas bé, el perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Has provat de desbloquejar la tauleta incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has provat de desbloquejar el telèfon incorrectament <xliff:g id="NUMBER">%d</xliff:g> vegades. El perfil professional se suprimirà, juntament amb totes les dades que contingui."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%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">%d</xliff:g> segons."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%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">%d</xliff:g> segons."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"El codi PIN de la SIM no és correcte. Has de contactar amb l\'operador de telefonia mòbil per desbloquejar el dispositiu."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 23e1420..44c7f27 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Znovu zadejte správný kód PUK. Opakovanými pokusy SIM kartu trvale deaktivujete."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kódy PIN se neshodují."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Příliš mnoho pokusů o nakreslení gesta"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávný kód PIN. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně zadali heslo. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste zadali nesprávné bezpečnostní gesto. \n\nZkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%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="1843331751334128428">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%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="6945823186629369880">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Uživatel bude odstraněn, čímž budou smazána všechna jeho data."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Již jste se <xliff:g id="NUMBER">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Uživatel bude odstraněn, čímž budou smazána všechna jeho data."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout tablet nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Již jste se <xliff:g id="NUMBER_0">%d</xliff:g>krát pokusili odemknout telefon nesprávným způsobem. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech bude pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 pracovní profil odstraněn, čímž se smažou všechna jeho data."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%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">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%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">%d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. 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="1437638152015574839">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index 2c39241..b81305b 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Indtast den korrekte PUK-kode. Gentagne forsøg vil permanent deaktivere SIM-kortet."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pinkoderne stemmer ikke overens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøg på at tegne mønstret korrekt"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har indtastet en forkert pinkode <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. \n\nPrøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg nulstilles denne tablet, hvilket vil slette alle dens data."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg nulstilles denne telefon, hvilket vil slette alle dens data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Du har forsøgt at låse tabletten forkert op <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 vil slette alle dens data."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har forsøgt at låse telefonen forkert op <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 vil slette alle dens data."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Tabletten nulstilles, hvilket vil slette alle dens data."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Telefonen nulstilles, hvilket vil slette alle dens data."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes denne bruger, hvilket vil slette alle brugerdata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har forsøgt at låse tabletten forkert op <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 vil slette alle brugerdata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har forsøgt at låse telefonen forkert op <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 vil slette alle brugerdata."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Brugeren fjernes, hvilket vil slette alle brugerdata."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Brugeren fjernes, hvilket vil slette alle brugerdata."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter endnu <xliff:g id="NUMBER_1">%d</xliff:g> mislykkede forsøg fjernes arbejdsprofilen, hvilket vil slette alle profildata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har forsøgt at låse tabletten forkert op <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 arbejdsprofilen, hvilket vil slette alle profildata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har forsøgt at låse telefonen forkert op <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 arbejdsprofilen, hvilket vil slette alle profildata."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du har forsøgt at låse tabletten forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har forsøgt at låse telefonen forkert op <xliff:g id="NUMBER">%d</xliff:g> gange. Arbejdsprofilen fjernes, hvilket vil slette alle profildata."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-mailkonto\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg vil du blive bedt om at låse din tablet op ved hjælp af en e-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="1437638152015574839">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en e-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="30531039455764924">"Forkert pinkode til SIM-kort. Du skal nu kontakte dit mobilselskab for at låse din enhed op."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index 737f533..40ddfc2 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Geben Sie 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="7003469261464593516">"PIN-Codes stimmen nicht überein"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zu viele Musterversuche"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%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="1843331751334128428">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird dieses Telefon zurückgesetzt. Dadurch werden alle Gerätedaten gelöscht."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch eingegeben.\n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. \n\nVersuchen Sie es in <xliff:g id="NUMBER_1">%2$d</xliff:g> Sekunden erneut."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sie haben <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="1843331751334128428">"Sie haben <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="258925501999698032">"Sie haben <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="7154028908459817066">"Sie haben <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="6159955099372112688">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%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="6945823186629369880">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"Sie haben <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="6945823186629369880">"Sie haben <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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Sie haben <xliff:g id="NUMBER">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Dieser Nutzer wird nun entfernt und alle Nutzerdaten werden gelöscht."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Tablet zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sie haben <xliff:g id="NUMBER_0">%d</xliff:g>-mal erfolglos versucht, das Telefon zu entsperren. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen wird das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sie haben <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 das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sie haben <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 das Arbeitsprofil entfernt. Dadurch werden alle Profildaten gelöscht."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Sie haben <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="4951507352869831265">"Sie haben <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="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr 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 werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr 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 werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuchen Sie es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Falscher PIN-Code der SIM-Karte. Bitte wenden Sie sich an Ihren Mobilfunkanbieter, damit er Ihr Gerät entsperrt."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Falscher PIN-Code der SIM-Karte. Sie haben noch <xliff:g id="NUMBER_1">%d</xliff:g> Versuche.</item>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index b915275..dc6cc05 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Εισαγάγετε ξανά τον κωδικό PUK. Οι επαναλαμβανόμενες προσπάθειες θα απενεργοποιήσουν οριστικά την κάρτα SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Δεν υπάρχει αντιστοιχία των κωδικών PIN"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Πάρα πολλές προσπάθειες μοτίβου"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Έχετε πληκτρολογήσει εσφαλμένα τον κωδικό σας PIN <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <xliff:g id="NUMBER_0">%d</xliff:g> φορές. \n\nΔοκιμάστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλετπα."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτό το tablet θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Έχετε πληκτρολογήσει εσφαλμένα τον κωδικό σας 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="7813713389422226531">"Έχετε πληκτρολογήσει τον κωδικό πρόσβασης εσφαλμένα <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="74089475965050805">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος <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="8774056606869646621">"Δοκιμάσατε να ξεκλειδώσετε το 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="1843331751334128428">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <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="258925501999698032">"Δοκιμάσατε να ξεκλειδώσετε αυτό το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το tablet θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτό το τηλέφωνο θα ρυθμιστεί εκ νέου, και έτσι θα διαγραφούν όλα τα δεδομένα του."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Δοκιμάσατε να ξεκλειδώσετε το 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="6945823186629369880">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <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_erasing_user" product="tablet" msgid="3963486905355778734">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Αυτός ο χρήστης θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα χρήστη."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER_0">%d</xliff:g> φορές χωρίς επιτυχία. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ακόμα ανεπιτυχείς δοκιμές, το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Δοκιμάσατε να ξεκλειδώσετε το 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_profile" product="default" msgid="6853071165802933545">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Δοκιμάσατε να ξεκλειδώσετε το tablet <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Δοκιμάσατε να ξεκλειδώσετε το τηλέφωνο <xliff:g id="NUMBER">%d</xliff:g> φορές χωρίς επιτυχία. Το προφίλ εργασίας θα καταργηθεί, και έτσι θα διαγραφούν όλα τα δεδομένα προφίλ."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το tablet σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε να συνδεθείτε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <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="1437638152015574839">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <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="30531039455764924">"Λανθασμένος κωδικός PIN κάρτας SIM. Θα πρέπει να επικοινωνήσετε με τον πάροχο κινητής τηλεφωνίας σας για να ξεκλειδώσετε τη συσκευή σας."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Λανθασμένος κωδικός PIN κάρτας SIM. Απομένουν άλλες <xliff:g id="NUMBER_1">%d</xliff:g> προσπάθειες. </item>
diff --git a/packages/Keyguard/res/values-en-rAU/strings.xml b/packages/Keyguard/res/values-en-rAU/strings.xml
index 0979d9a..5aec0e9 100644
--- a/packages/Keyguard/res/values-en-rAU/strings.xml
+++ b/packages/Keyguard/res/values-en-rAU/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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="3963486905355778734">"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="7729009752252111673">"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="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="4621778507387853694">"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="6853071165802933545">"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="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"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="6721575017538162249">
<item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index 0979d9a..5aec0e9 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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="3963486905355778734">"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="7729009752252111673">"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="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="4621778507387853694">"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="6853071165802933545">"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="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"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="6721575017538162249">
<item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index 0979d9a..5aec0e9 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Re-enter the correct PUK code. Repeated attempts will permanently disable the SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN codes do not match"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Too many pattern attempts"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"You have incorrectly typed your PIN <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"You have incorrectly typed your password <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. \n\nTry again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="1843331751334128428">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, this phone will be reset, which will delete all its data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6945823186629369880">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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="3963486905355778734">"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="7729009752252111673">"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="4621778507387853694">"You have incorrectly attempted to unlock the tablet <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="6853071165802933545">"You have incorrectly attempted to unlock the phone <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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="tablet" msgid="4621778507387853694">"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="6853071165802933545">"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="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%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">%d</xliff:g> seconds."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"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="6721575017538162249">
<item quantity="other">Incorrect SIM PIN code, you have <xliff:g id="NUMBER_1">%d</xliff:g> remaining attempts.</item>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index 0becc66..bbfda156 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Los códigos PIN no coinciden."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de ingresar el patrón"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nVuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá la tablet y se perderán todos los datos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el teléfono y se perderán todos los datos."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escribiste incorrectamente tu PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \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="7813713389422226531">"Escribiste incorrectamente tu contraseña <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \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="74089475965050805">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \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="8774056606869646621">"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 y se perderán todos los datos."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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 y se perderán todos los datos."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá la tablet y se perderán todos los datos."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se restablecerá el teléfono y se perderán todos los datos."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el usuario y se perderán todos los datos de usuario."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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 eliminará el usuario y se perderán todos los datos de usuario."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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 eliminará el usuario y se perderán todos los datos de usuario."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el usuario y se perderán todos los datos de usuario."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el usuario y se perderán todos los datos de usuario."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Intentaste desbloquear la tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de manera incorrecta. Después de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Intentaste desbloquear la tablet <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Intentaste desbloquear el teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de manera incorrecta. Se eliminará el perfil de trabajo y se perderán todos los datos de perfil."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tablet mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 el uso de una cuenta de correo.\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="1437638152015574839">"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 el uso de una cuenta de correo.\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="30531039455764924">"El código PIN de la tarjeta SIM es incorrecto. Debes comunicarte con el proveedor para desbloquear el dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">El código PIN de la tarjeta SIM es incorrecto. Tienes <xliff:g id="NUMBER_1">%d</xliff:g> intentos más.</item>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 6f37d8b..d329c2ab 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Vuelve a introducir el código PUK correcto. Si introduces un código incorrecto varias veces, se inhabilitará la tarjeta SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Los códigos PIN no coinciden."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiados intentos incorrectos de crear el patrón"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el tablet, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos sus datos."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Has introducido un código PIN incorrecto <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar tu patrón de desbloqueo. \n\nInténtalo de nuevo en <xliff:g id="NUMBER_1">%2$d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el tablet, lo que borrará todos sus datos."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se restablecerá el teléfono, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este tablet se eliminará, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este teléfono se eliminará, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará a este usuario, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este usuario se eliminará, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. Este usuario se eliminará, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Si se producen <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se eliminará el perfil de trabajo, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Has intentado desbloquear el tablet de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Has intentado desbloquear el teléfono de forma incorrecta <xliff:g id="NUMBER">%d</xliff:g> veces. El perfil de trabajo se eliminará, lo que borrará todos sus datos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Has fallado <xliff:g id="NUMBER_0">%d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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, deberás usar una cuenta de correo electrónico para desbloquear el tablet.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"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, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Código PIN de la tarjeta SIM incorrecto. Debes ponerte en contacto con tu operador para desbloquear el dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Código PIN de la tarjeta SIM incorrecto. Te quedan <xliff:g id="NUMBER_1">%d</xliff:g> intentos.</item>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index 89ffbde..e3ad33a 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Sisestage uuesti õige PUK-kood. Korduvkatsete korral keelatakse SIM jäädavalt."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koodid ei ole vastavuses"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liiga palju mustrikatseid"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olete PIN-koodi <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti.\n\nProovige <xliff:g id="NUMBER_1">%d</xliff:g> sekundi pärast uuesti."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%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="1843331751334128428">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"Olete parooli <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti sisestanud. \n\nProovige uuesti <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundi pärast."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti.\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="8774056606869646621">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <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="1843331751334128428">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <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="258925501999698032">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Tahvelarvuti lähtestatakse ja kõik selle andmed kustutatakse."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Telefon lähtestatakse ja kõik selle andmed kustutatakse."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Kasutaja eemaldatakse ja kõik kasutaja andmed kustutatakse."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Olete püüdnud <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti tahvelarvutit avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Olete püüdnud <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti telefoni avada. Pärast <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti tahvelarvutit avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Olete püüdnud <xliff:g id="NUMBER">%d</xliff:g> korda valesti telefoni avada. Tööprofiil eemaldatakse ja kõik profiili andmed kustutatakse."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil tahvelarvuti avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%d</xliff:g> sekundi pärast."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"Vale SIM-i PIN-kood, seadme avamiseks peate nüüd ühendust võtma oma operaatoriga."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Vale SIM-kaardi PIN-kood, teil on jäänud veel <xliff:g id="NUMBER_1">%d</xliff:g> katset.</item>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index 3a740f6..19531bd 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Idatzi berriro PUK kode zuzena. Hainbat saiakera oker eginez gero, betirako desgaituko da SIMa."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodeak ez datoz bat"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Eredua marrazteko saiakera gehiegi egin dira"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%d</xliff:g> segundo barru."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \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="7813713389422226531">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \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="74089475965050805">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \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="8774056606869646621">"<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, tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<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, telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Tableta berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Telefonoa berrezarri egingo da eta, ondorioz, datu guztiak ezabatuko dira."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<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, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<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, erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Erabiltzailea kendu egingo da eta, ondorioz, erabiltzailearen datu guztiak ezabatuko dira."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara tableta desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> aldiz saiatu zara telefonoa desblokeatzen, baina huts egin duzu denetan. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz huts egiten baduzu, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<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, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<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, laneko profila kendu egingo da eta, ondorioz, profileko datu guztiak ezabatuko dira."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<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="4951507352869831265">"<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="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, tableta posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%d</xliff:g> segundo barru."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten 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="1437638152015574839">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten 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="30531039455764924">"SIM txartelaren PIN kodea okerra da. Gailua desblokeatzeko, jarri operadorearekin harremanetan."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM txartelaren PIN kodea okerra da. <xliff:g id="NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu gailua desblokeatzeko.</item>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 975fe7f..75e38a2 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"پین کد صحیح را دوباره وارد کنید. تلاشهای مکرر بهطور دائم سیم کارت را غیرفعال خواهد کرد."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"پین کدها منطبق نیستند"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"تلاشهای زیادی برای کشیدن الگو صورت گرفته است"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"گذرواژه خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه تایپ کردید. \n\nپس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدید. \n\nلطفاً پس از <xliff:g id="NUMBER_1">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این رایانه لوحی بازنشانی میشود که با آن کل اطلاعاتش حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، تلفن بازنشانی میشود که با آن کل اطلاعاتش حذف میشود."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"پین خود را <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="7813713389422226531">"گذرواژه خود را <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="74089475965050805">"الگوی بازگشایی قفل خود را <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="8774056606869646621">"<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="1843331751334128428">"<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="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. این رایانه لوحی بازنشانی میشود که با آن همه اطلاعاتش حذف میشود."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. این تلفن بازنشانی میشود که با آن همه اطلاعاتش حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این کاربر حذف میشود که با آن کل اطلاعات کاربر حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، این کاربر حذف میشود که با آن کل اطلاعات کاربر حذف میشود."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<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="6945823186629369880">"<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_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. این کاربر حذف میشود که با آن همه اطلاعات کاربر حذف میشود."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. این کاربر حذف میشود که با آن همه اطلاعات کاربر حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، نمایه کار حذف میشود که با آن کل اطلاعات نمایه حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق دیگر، نمایه کار حذف میشود که با آن کل اطلاعات نمایه حذف میشود."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<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_profile" product="default" msgid="6853071165802933545">"<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_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل رایانه لوحی داشتهاید. نمایه کار حذف میشود که با آن همه اطلاعات نمایه حذف میشود."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> تلاش ناموفق برای باز کردن قفل تلفن داشتهاید. نمایه کار حذف میشود که با آن همه اطلاعات نمایه حذف میشود."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدهاید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <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="1437638152015574839">"شما الگوی بازگشایی قفل خود را <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="30531039455764924">"کد پین سیم کارت اشتباه است، اکنون برای گشودن قفل دستگاهتان باید با شرکت مخابراتی تماس بگیرید."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">کد پین سیمکارت اشتباه است، <xliff:g id="NUMBER_1">%d</xliff:g> بار دیگر میتوانید تلاش کنید.</item>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index 94c8d62..e3e6e64 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN-koodit eivät täsmää"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Liikaa kuvionpiirtoyrityksiä"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Olet kirjoittanut PIN-koodin väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Olet kirjoittanut salasanan väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Olet piirtänyt lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. \n\nYritä uudelleen <xliff:g id="NUMBER_1">%d</xliff:g> sekunnin kuluttua."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä tabletti nollataan ja kaikki sen tiedot poistetaan."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä puhelin nollataan ja kaikki sen tiedot poistetaan."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, tämä käyttäjä ja kaikki käyttäjän tiedot poistetaan."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä käyttäjä ja kaikki sen tiedot poistetaan."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER">%d</xliff:g> kertaa. Tämä käyttäjä ja kaikki sen tiedot poistetaan."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Yritit avata tabletin lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Yritit avata puhelimen lukituksen virheellisillä tiedoilla <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos teet vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> epäonnistunutta yritystä, työprofiili ja kaikki sen tiedot poistetaan."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 poistamaan tablet-laitteesi 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="1437638152015574839">"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 poistamaan 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index c8afb91..e233af2 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un NIP incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%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="1843331751334128428">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi 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="7813713389422226531">"Vous avez saisi 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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%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="6945823186629369880">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cet utilisateur sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cet utilisateur sera supprimé, ce qui entraîne la suppression de toutes ses données."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller cette tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller ce téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Après <xliff:g id="NUMBER_1">%d</xliff:g> tentative(s) infructueuse(s) supplémentaire(s), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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), le profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 profil professionnel sera supprimé, ce qui entraînera la suppression de toutes ses données."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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\n Veuillez 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="1437638152015574839">"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\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index afefc9a..b7590bd 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Veuillez saisir de nouveau le code PUK correct. Des tentatives répétées désactivent définitivement la carte SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Les codes PIN ne correspondent pas."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Trop de tentatives."</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. \n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises.\n\nVeuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, cette tablette 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="1843331751334128428">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, ce téléphone sera réinitialisé et toutes les données qu\'il contient seront supprimées."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Vous avez saisi un code PIN 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="7813713389422226531">"Vous avez saisi 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="74089475965050805">"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="8774056606869646621">"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, cette tablette 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="1843331751334128428">"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 téléphone 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="258925501999698032">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Cette tablette 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="7154028908459817066">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce téléphone 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="6159955099372112688">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%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="6945823186629369880">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce compte utilisateur et toutes les données associées vont être supprimés."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER">%d</xliff:g> reprises. Ce compte utilisateur et toutes les données associées vont être supprimés."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Vous avez tenté de déverrouiller la tablette à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Vous avez tenté de déverrouiller le téléphone à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, le profil professionnel et toutes les données associées seront supprimés."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, le profil professionnel et toutes les données associées seront supprimés."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, le profil professionnel et toutes les données associées seront supprimés."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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\n Veuillez 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="1437638152015574839">"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\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<item quantity="one">Code PIN de la carte SIM erroné. Il vous reste <xliff:g id="NUMBER_1">%d</xliff:g> tentative.</item>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 4713abf..bd7f1f2 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Os códigos PIN non coinciden"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Tentaches debuxar o padrón moitas veces"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Introduciches o PIN incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Introduciches o contrasinal incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Debuxaches incorrectamente o padrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. \n\nTéntao de novo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, restablecerase o tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, restablecerase o teléfono e, por conseguinte, eliminaranse todos os seus datos."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Tentaches desbloquear o tablet <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 tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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="258925501999698032">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Restablecerase o tablet e, por conseguinte, eliminaranse todos os seus datos."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"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="6159955099372112688">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentaches desbloquear o tablet <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, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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, eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase este usuario e, por conseguinte, todos os datos do usuario."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentaches desbloquear o tablet <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER_0">%d</xliff:g> veces de forma incorrecta. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentaches desbloquear o tablet <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, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tentaches desbloquear o tablet <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Tentaches desbloquear o teléfono <xliff:g id="NUMBER">%d</xliff:g> veces de forma incorrecta. Eliminarase o perfil de traballo e, por conseguinte, todos os datos do perfil."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos máis, terás que desbloquear o tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%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 dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 tablet a través dunha unha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"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 dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"O código PIN da SIM non é correcto. Agora debes contactar co teu operador para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-gu-rIN/strings.xml b/packages/Keyguard/res/values-gu-rIN/strings.xml
index f74c8aa..8ab8249 100644
--- a/packages/Keyguard/res/values-gu-rIN/strings.xml
+++ b/packages/Keyguard/res/values-gu-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"સાચો PUK કોડ ફરીથી દાખલ કરો. પુનરાવર્તિત પ્રયાસો SIM ને કાયમી રીતે અક્ષમ કરશે."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN કોડ્સ મેળ ખાતા નથી"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ઘણા બધા પેટર્ન પ્રયાસો"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારો PIN લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારો પાસવર્ડ લખ્યો છે. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે તમારી અનલૉક પેટર્ન દોરી. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"તમે ટેબ્લેટને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ ટેબ્લેટ ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"તમે ફોનને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસ પછી, આ ફોન ફરીથી સેટ કરવામાં આવશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"તમે <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="7813713389422226531">"તમે <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="74089475965050805">"તમે <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="8774056606869646621">"તમે ટેબ્લેટને અનલૉક કરવા માટે <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="1843331751334128428">"તમે ફોનને અનલૉક કરવા માટે <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="258925501999698032">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ટેબ્લેટને અનલૉક કરવાનો પ્રયાસ કર્યો. આ ટેબ્લેટ ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ફોનને અનલૉક કરવાનો પ્રયાસ કર્યો. આ ફોન ફરીથી સેટ થશે, જે તેનો તમામ ડેટા કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"તમે ટેબ્લેટને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસો પછી, આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"તમે ફોનને અનલૉક કરવા માટે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો. <xliff:g id="NUMBER_1">%d</xliff:g> વધુ અસફળ પ્રયાસ પછી, આ વપરાશકર્તા દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટા કાઢી નાખશે."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"તમે ટેબ્લેટને અનલૉક કરવા માટે <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="6945823186629369880">"તમે ફોનને અનલૉક કરવા માટે <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_erasing_user" product="tablet" msgid="3963486905355778734">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ટેબ્લેટને અનલૉક કરવાનો પ્રયાસ કર્યો. આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ફોનને અનલૉક કરવાનો પ્રયાસ કર્યો. આ વપરાશકર્તાને દૂર કરવામાં આવશે, જે તમામ વપરાશકર્તા ડેટાને કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"તમે ટેબ્લેટને અનલૉક કરવાનો <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો છે. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"તમે ફોનને અનલૉક કરવાનો <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે પ્રયાસ કર્યો છે. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"તમે ટેબ્લેટને અનલૉક કરવાનો <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_profile" product="default" msgid="6853071165802933545">"તમે ફોનને અનલૉક કરવાનો <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_erasing_profile" product="tablet" msgid="4686386497449912146">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ટેબ્લેટને અનલૉક કરવાનો પ્રયાસ કર્યો. કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"તમે <xliff:g id="NUMBER">%d</xliff:g> વખત ખોટી રીતે ફોનને અનલૉક કરવાનો પ્રયાસ કર્યો. કાર્ય પ્રોફાઇલ દૂર કરવામાં આવશે, જે તમામ પ્રોફાઇલ ડેટાને કાઢી નાખશે."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"તમે <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે અનલૉક પેટર્ન દોરી છે. વધુ <xliff:g id="NUMBER_1">%d</xliff:g> વખત અસફળ પ્રયાસો પછી, તમને એક ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને તમારા ટેબ્લેટને અનલૉક કરવા માટે પૂછવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> સેકંડમાં ફરી પ્રયાસ કરો."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"તમે તમારી અનલૉક પેટર્ન <xliff:g id="NUMBER_0">%d</xliff:g> વખત ખોટી રીતે દોરી. હજી <xliff:g id="NUMBER_1">%d</xliff:g> અસફળ પ્રયાસ પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> સેકંડમાં ફરીથી પ્રયાસ કરો."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"તમે <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="1437638152015574839">"તમે તમારી અનલૉક પેટર્ન <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="30531039455764924">"ખોટો SIM PIN કોડ, તમારે હવે તમારું ઉપકરણ અનલૉક કરવા માટે તમારા કેરિઅરનો સંપર્ક કરવો આવશ્યક છે."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">ખોટો SIM PIN કોડ, તમારી પાસે <xliff:g id="NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે.</item>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 612d16c..92d2f7a 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"सही PUK कोड पुन: डालें. बार-बार प्रयास करने से सिम स्थायी रूप से अक्षम हो जाएगी."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड का मिलान नहीं होता"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बहुत अधिक आकार प्रयास"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना PIN <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आप अपना पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से लिख चुके हैं. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपने अपना अनलॉक आकार <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस टैबलेट को रीसेट कर दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस फ़ोन को रीसेट कर दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आप अपना 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="7813713389422226531">"आप अपना पासवर्ड <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="74089475965050805">"आपने अपना अनलॉक आकार <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="8774056606869646621">"आपने टैबलेट को अनलॉक करने के लिए <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="1843331751334128428">"आपने फ़ोन को अनलॉक करने के लिए <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="258925501999698032">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. इस टैबलेट को रीसेट कर दिया जाएगा, जिससे उसका सभी डेटा हट जाएगा."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. इस फ़ोन को रीसेट कर दिया जाएगा, जिससे उसका सभी डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"आपने टैबलेट को अनलॉक करने के लिए <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="6945823186629369880">"आपने फ़ोन को अनलॉक करने के लिए <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_erasing_user" product="tablet" msgid="3963486905355778734">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. इस उपयोगकर्ता को निकाल दिया जाएगा, जिससे सभी उपयोगकर्ता डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"आपके डिवाइस ने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से प्रयास किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"आपने टैबलेट को अनलॉक करने के लिए <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_profile" product="default" msgid="6853071165802933545">"आपके डिवाइस ने फ़ोन को अनलॉक करने के लिए <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_erasing_profile" product="tablet" msgid="4686386497449912146">"आपने टैबलेट को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपने फ़ोन को अनलॉक करने के लिए <xliff:g id="NUMBER">%d</xliff:g> बार गलत तरीके से प्रयास किया है. कार्य प्रोफ़ाइल को निकाल दिया जाएगा, जिससे सभी प्रोफ़ाइल डेटा हट जाएगा."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक आकार को <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="1437638152015574839">"आपने अपने अनलॉक आकार को <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="30531039455764924">"गलत सिम PIN कोड अपने डिवाइस को अनलॉक करने के लिए अब आपको अपने वाहक से संपर्क करना होगा."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">गलत सिम PIN कोड, आपके पास <xliff:g id="NUMBER_1">%d</xliff:g> प्रयास शेष हैं.</item>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index d77176b..c716746 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN kodovi nisu jednaki"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja iscrtavanja obrasca"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali PIN <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Netočno ste napisali zaporku <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%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="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Netočno ste napisali 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="7813713389422226531">"Netočno ste napisali zaporku <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="74089475965050805">"Netočno ste iscrtali obrazac 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="8774056606869646621">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. 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="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. 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="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. 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="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. 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="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%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="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. 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="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. 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_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Taj će se korisnik ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati tablet. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> put/a ste neuspješno pokušali otključati telefon. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja radni će se profil ukloniti, a time će se izbrisati i svi njegovi podaci."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati tablet. 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="4951507352869831265">"<xliff:g id="NUMBER">%d</xliff:g> put/a ste neuspješno pokušali otključati telefon. 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="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> morat ćete otključati tabletno računalo 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="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> 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="30531039455764924">"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="6721575017538162249">
<item quantity="one">Netočan PIN kôd SIM kartice; imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 55cf24f..2ecfb21 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Adja meg újra a helyes PUK kódot. Az ismételt próbálkozással véglegesen letiltja a SIM kártyát."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"A PIN kódok nem egyeznek."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Túl sok mintarajzolási próbálkozás"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg PIN kódját. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül adta meg a jelszót. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal rosszul rajzolta le feloldási mintát. \n\nPróbálja újra <xliff:g id="NUMBER_1">%d</xliff:g> másodperc múlva."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a táblagépet a gyári állapotba; ekkor az összes adat törlődik róla."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a telefont a gyári állapotba; ekkor az összes adat törlődik róla."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül adta meg PIN kódjá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_password_attempts_dialog_message" msgid="7813713389422226531">"<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="74089475965050805">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal rosszul rajzolta le 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="8774056606869646621">"<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. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a táblagépet a gyári állapotba; ekkor az összes adat törlődik róla."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer visszaállítja a telefont a gyári állapotba; ekkor az összes adat törlődik róla."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<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 a gyári állapotba, és annak összes adata törlődik."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"<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 a gyári állapotba, és annak összes adata törlődik."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<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. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja ezt a felhasználót; ekkor összes felhasználói adata törlődni fog."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<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 felhasználót, és annak összes felhasználói adata törlődik."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<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 felhasználót, és annak összes felhasználói adata törlődik."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a táblagép zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<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. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal próbálkozott sikertelenül a telefon zárolásának feloldásával. <xliff:g id="NUMBER_1">%2$d</xliff:g> további sikertelen kísérlet után a rendszer eltávolítja munkahelyi profilját; ekkor összes profiladata törlődni fog."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<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 munkahelyi profilját, és összes profiladata törlődik."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"<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 munkahelyi profilját, és összes profiladata törlődik."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<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 egy e-mail fiók használatával kell feloldania a táblagépét.\n\n Kérjük, pró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="1437638152015574839">"<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 egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, pró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="30531039455764924">"Helytelen PIN-kód a SIM kártyához; vegye fel a kapcsolatot szolgáltatójával az eszköz feloldásához."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">A SIM kártya PIN kódja helytelen. <xliff:g id="NUMBER_1">%d</xliff:g> próbálkozás maradt.</item>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index 7c771ca..e6692af 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Վերամուտքագրեք ճիշտ PUK ծածկագիրը: Կրկնվող փորձերը ընդմիշտ կկասեցնեն SIM քարտը:"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ծածկագրերը չեն համընկնում"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Չափից շատ սխեմայի փորձեր"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք մուտքագրել ձեր PIN-ը: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման սխեման: \n\nՓորձեք կրկին <xliff:g id="NUMBER_1">%d</xliff:g> վայրկյանից:"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս գրասալիկը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Դուք <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="7813713389422226531">"Դուք սխալ եք մուտքագրել ձեր գաղտնաբառը <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="74089475965050805">"Դուք <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="8774056606869646621">"Դուք կատարել եք գրասալիկն ապակողպելու <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="1843331751334128428">"Դուք կատարել եք հեռախոսն ապակողպելու <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="258925501999698032">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս գրասալիկը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Այս հեռախոսը կվերակայվի և բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո այս օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Դուք կատարել եք գրասալիկն ապակողպելու <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="6945823186629369880">"Դուք կատարել եք հեռախոսն ապակողպելու <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_erasing_user" product="tablet" msgid="3963486905355778734">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Օգտվողը կհեռացվի և օգտվողի բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER_0">%d</xliff:g> անհաջող փորձ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Դուք կատարել եք գրասալիկն ապակողպելու <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_profile" product="default" msgid="6853071165802933545">"Դուք կատարել եք հեռախոսն ապակողպելու <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Դուք կատարել եք գրասալիկն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Դուք կատարել եք հեռախոսն ապակողպելու <xliff:g id="NUMBER">%d</xliff:g> անհաջող փորձ: Աշխատանքային պրոֆիլը կհեռացվի և պրոֆիլի բոլոր տվյալները կջնջվեն:"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <xliff:g id="NUMBER_0">%d</xliff:g> անգամ: Եվս <xliff:g id="NUMBER_1">%d</xliff:g> անհաջող փորձից հետո ձեզանից կպահանջվի ապակողպել ձեր գրասալիկը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Դուք <xliff:g id="NUMBER_0">%d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%d</xliff:g> վայրկյանից:"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Դուք սխալ եք հավաքել ձեր ապակողպման սխեման <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="1437638152015574839">"Դուք <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="30531039455764924">"Սխալ SIM PIN կոդի պատճառով պետք է դիմեք ձեր օպերատորին՝ սարքն արգելաբացելու համար:"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">SIM PIN կոդը սխալ է: Մնաց <xliff:g id="NUMBER_1">%d</xliff:g> փորձ:</item>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index dbe01e7..4b18dbc 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Kode PIN tidak cocok"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak upaya pola"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik PIN. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah mengetik sandi. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. \n\nCoba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%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="1843331751334128428">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, ponsel ini akan disetel ulang, sehingga semua datanya akan dihapus."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%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="6945823186629369880">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Pengguna ini akan dihapus, sehingga menghapus semua data pengguna."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Sudah <xliff:g id="NUMBER">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Pengguna ini akan dihapus, sehingga menghapus semua data pengguna."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci tablet dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Sudah <xliff:g id="NUMBER_0">%d</xliff:g> kali Anda berupaya membuka kunci ponsel dengan tidak benar. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya yang tidak berhasil, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, profil kerja akan dihapus, sehingga semua data profil akan dihapus."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Kode PIN SIM salah. Hubungi operator untuk membuka kunci perangkat."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Kode PIN SIM salah, sisa <xliff:g id="NUMBER_1">%d</xliff:g> percobaan.</item>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index 23e135b..4b8b702 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN-númerin stemma ekki"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Of margar tilraunir til að teikna mynstur"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Þú hefur slegið inn rangt PIN-númer <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Þú hefur slegið inn rangt aðgangsorð <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. \n\nReyndu aftur eftir <xliff:g id="NUMBER_1">%d</xliff:g> sekúndur."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%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="1843331751334128428">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Þú 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="7813713389422226531">"Þú 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="74089475965050805">"Þú 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="8774056606869646621">"Þú 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="1843331751334128428">"Þú 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="258925501999698032">"Þú 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="7154028908459817066">"Þú 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="6159955099372112688">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%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="6945823186629369880">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"Þú 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="6945823186629369880">"Þú 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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Notandinn verður fjarlægður, með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Þú hefur gert <xliff:g id="NUMBER">%d</xliff:g> árangurslausar tilraunir til að opna símann. Notandinn verður fjarlægður, með þeim afleiðingum að öllum notandagögnum verður eytt."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna spjaldtölvuna. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Þú hefur gert <xliff:g id="NUMBER_0">%d</xliff:g> árangurslausar tilraunir til að opna símann. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Þú 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 vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Þú 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 vinnusniðið fjarlægt með þeim afleiðingum að öllum gögnum þess verður eytt."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Þú 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="4951507352869831265">"Þú 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="3253575572118914370">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%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">%d</xliff:g> sekúndur."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%d</xliff:g> sekúndur."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Þú 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="1437638152015574839">"Þú 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 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="30531039455764924">"Rangt PIN-númer SIM-korts. Þú þarft núna að hafa samband við símafyrirtækið þitt til að taka tækið úr lás."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 98cb0b2..08d4116 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"I codici PIN non corrispondono"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Troppi tentativi di inserimento della sequenza"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Hai digitato il tuo PIN <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Hai digitato la tua password <xliff:g id="NUMBER_0">%d</xliff:g> volte in modo errato. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. \n\nRiprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%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="1843331751334128428">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il telefono verrà ripristinato e verranno quindi eliminati tutti i relativi dati."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"<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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%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="6945823186629369880">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER">%d</xliff:g> volte. Questo utente verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Hai tentato di sbloccare il tablet senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Hai tentato di sbloccare il telefono senza riuscirci per <xliff:g id="NUMBER_0">%d</xliff:g> volte. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, il profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 profilo di lavoro verrà rimosso e verranno quindi eliminati tutti i dati associati."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%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">%d</xliff:g> secondi."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%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">%d</xliff:g> secondi."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<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="1437638152015574839">"<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="30531039455764924">"Codice PIN della SIM errato. Devi contattare l\'operatore per sbloccare il dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index 7ffa676..b9cdf5e 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"הזן מחדש את קוד PUK הנכון. ניסיונות חוזרים ישביתו לצמיתות את כרטיס ה-SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"קודי ה-PIN אינם תואמים"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ניסיונות רבים מדי לשרטוט קו ביטול נעילה."</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"הקלדת מספר PIN שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"הקלדת סיסמה שגויה <xliff:g id="NUMBER_0">%d</xliff:g> פעמים.\n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. \n\nנסה שוב בעוד <xliff:g id="NUMBER_1">%d</xliff:g> שניות."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, טאבלט זה יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, טלפון זה יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"הקלדת מספר 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="7813713389422226531">"הקלדת סיסמה שגויה <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="74089475965050805">"שרטטת את קו ביטול הנעילה באופן שגוי <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="8774056606869646621">"ניסית לבטל את נעילת הטאבלט <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="1843331751334128428">"ניסית לבטל את נעילת הטלפון <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="258925501999698032">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. הטאבלט יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. הטלפון יאופס וכתוצאה מכך כל הנתונים שלו יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ניסית לבטל את נעילת הטאבלט <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="6945823186629369880">"ניסית לבטל את נעילת הטלפון <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_erasing_user" product="tablet" msgid="3963486905355778734">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. משתמש זה יוסר וכתוצאה מכך כל נתוני המשתמש יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER_0">%d</xliff:g> פעמים באופן שגוי. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ניסית לבטל את נעילת הטאבלט <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_profile" product="default" msgid="6853071165802933545">"ניסית לבטל את נעילת הטלפון <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ניסית לבטל את נעילת הטאבלט <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ניסית לבטל את נעילת הטלפון <xliff:g id="NUMBER">%d</xliff:g> פעמים באופן שגוי. פרופיל העבודה יוסר וכתוצאה מכך כל נתוני הפרופיל יימחקו."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <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="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <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="30531039455764924">"מספר PIN שגוי של כרטיס ה-SIM. עליך ליצור כעת קשר עם הספק על מנת לבטל את נעילת המכשיר."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="two">קוד PIN שגוי של כרטיס SIM. נותרו לך <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות.</item>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index 3230beb..adfefcb 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"正しいPUKコードを再入力してください。誤入力を繰り返すと、SIMが永久に無効になるおそれがあります。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PINコードが一致しません"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"パターンの入力を所定の回数以上間違えました。"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PINの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"パスワードの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。\n\n<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度お試しください。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"タブレットのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このタブレットはリセットされ、データがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"携帯電話のロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、この携帯電話はリセットされ、データがすべて削除されます。"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"パスワードの入力を<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="74089475965050805">"ロック解除パターンの入力を<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="8774056606869646621">"タブレットのロック解除に<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="1843331751334128428">"携帯電話のロック解除に<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="258925501999698032">"タブレットのロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。このタブレットはリセットされ、データがすべて削除されます。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"携帯電話のロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。この携帯電話はリセットされ、データがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"タブレットのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"携帯電話のロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"タブレットのロック解除に<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="6945823186629369880">"携帯電話のロック解除に<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_erasing_user" product="tablet" msgid="3963486905355778734">"タブレットのロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"携帯電話のロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。このユーザーは削除され、ユーザーのデータがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"タブレットのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"スマートフォンのロック解除に<xliff:g id="NUMBER_0">%d</xliff:g>回失敗しました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回失敗すると、仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"タブレットのロック解除に<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_profile" product="default" msgid="6853071165802933545">"スマートフォンのロック解除に<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_erasing_profile" product="tablet" msgid="4686386497449912146">"タブレットのロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"スマートフォンのロック解除に<xliff:g id="NUMBER">%d</xliff:g>回失敗しました。仕事用プロファイルが削除され、プロファイルのデータがすべて削除されます。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度お試しください。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<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="1437638152015574839">"ロック解除パターンの入力を<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="30531039455764924">"SIM PINコードが無効です。お使いの端末をロック解除するには携帯通信会社にお問い合わせいただく必要があります。"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PINコードが無効です。入力できるのはあと<xliff:g id="NUMBER_1">%d</xliff:g>回です。</item>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index c9b31cd..78fc54b 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ხელახლა შეიყვანეთ სწორი PUK კოდი. რამდენიმე წარუმატებელი მცდელობა გამოიწვევს SIM ბარათის დაბლოკვას."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN კოდები არ ემთხვევა"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ნახატი ნიმუშის ძალიან ბევრი მცდელობა"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად შეიყვანეთ PIN კოდი. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ არასწორად დაბეჭდეთ თქვენი პაროლი. \n\nხელახლა სცადეთ <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"თქვენ <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ დახატეთ განბლოკვის ნიმუში. \n\nსცადეთ ხელახლა <xliff:g id="NUMBER_1">%d</xliff:g> წამში."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, ეს ტაბლეტი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ეს ტელეფონი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"თქვენ <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="7813713389422226531">"თქვენ <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="74089475965050805">"თქვენ <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="8774056606869646621">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <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="1843331751334128428">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <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="258925501999698032">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. ეს ტაბლეტი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. ეს ტელეფონი გადაიტვირთება, რაც წაშლის მის მთლიან მონაცემს."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება ეს მომხმარებელი და წაიშლება მომხმარებლის მთლიანი მონაცემი."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება ეს მომხმარებელი და წაიშლება მომხმარებლის მთლიანი მონაცემი."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <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="6945823186629369880">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <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_erasing_user" product="tablet" msgid="3963486905355778734">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. ეს მომხმარებელი ამოიშლება, რაც წაშლის მომხმარებლის მთლიან მონაცემს."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. ეს მომხმარებელი ამოიშლება, რაც წაშლის მომხმარებლის მთლიან მონაცემს."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება სამუშაო პროფილი და წაიშლება პროფილის მთლიანი მონაცემი."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი მცდელობის შემდეგ, ამოიშლება სამუშაო პროფილი და წაიშლება მთლიანი პროფილის მონაცემი."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <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_profile" product="default" msgid="6853071165802933545">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <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_erasing_profile" product="tablet" msgid="4686386497449912146">"თქვენ არასწორად სცადეთ ტაბლეტის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. სამუშაო პროფილი ამოიშლება, რაც წაშლის პროფილის მთლიან მონაცემს."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"თქვენ არასწორად სცადეთ ტელეფონის განბლოკვა <xliff:g id="NUMBER">%d</xliff:g> ჯერ. სამუშაო პროფილი ამოიშლება, რაც წაშლის პროფილის მთლიან მონაცემს."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g> ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ მოგთხოვთ ტაბლეტის განბლოკვას ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%d</xliff:g> წამში."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <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="1437638152015574839">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <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="30531039455764924">"SIM-ის არასწორი PIN კოდი. თქვენ ახლა მოგიწევთ მოწყობილობის განსაბლოკად მიმართოთ ოპერატორს."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM-ის PIN კოდი არასწორია. თქვენ დაგრჩათ <xliff:g id="NUMBER_1">%d</xliff:g> მცდელობა.</item>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index ea3992d..0d415ff 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Дұрыс PUK кодын қайта енгізіңіз. Әрекеттерді қайталау SIM картасының істен шығуына себеп болады."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN коды сәйкес емес."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Тым көп кескін әрекеттері"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN кодты <xliff:g id="NUMBER_0">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайталаңыз."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Құпия сөзді <xliff:g id="NUMBER_0">%d</xliff:g> рет қате тердіңіз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін қайталаңыз."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Құлыпты ашу өрнегін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате салдыңыз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундтан кейін әрекетті қайталаңыз."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Планшет бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы планшет қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы телефон қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"Құпия сөзді <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="74089475965050805">"Құлыпты ашу өрнегін <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="8774056606869646621">"Планшет бекітпесін ашуға <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="1843331751334128428">"Телефон бекітпесін ашуға <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="258925501999698032">"Планшет бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Осы планшет қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Телефон бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Осы телефон қалпына келтіріліп, оның бүкіл деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Планшет бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Планшет бекітпесін ашуға <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="6945823186629369880">"Телефон бекітпесін ашуға <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_erasing_user" product="tablet" msgid="3963486905355778734">"Планшет бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Телефон бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Осы пайдаланушы жойылып, бүкіл пайдаланушы деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Планшет бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Телефон бекітпесін ашуға <xliff:g id="NUMBER_0">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Тағы <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Планшет бекітпесін ашуға <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_profile" product="default" msgid="6853071165802933545">"Телефон бекітпесін ашуға <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Планшет бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефон бекітпесін ашуға <xliff:g id="NUMBER">%d</xliff:g> рет дұрыс емес әрекет жасадыңыз. Жұмыс профилі жойылып, бүкіл профиль деректері жойылады."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. After <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін планшетіңізді есептік жазба арқылы ашу өтінішін аласыз.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. After <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="1437638152015574839">"Бекітпені ашу кескінін <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="30531039455764924">"SIM PIN коды дұрыс емес, құрылғыны ашу үшін қызмет жабдықтаушыға хабарласаңыз."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN коды дұрыс емес, <xliff:g id="NUMBER_1">%d</xliff:g> әрекет қалды.</item>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 3803abf..1967246 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"បញ្ចូលកូដ PUK ម្ដងទៀត។ ការព្យាយាមដដែលច្រើនដឹងនឹងបិទស៊ីមកាតជាអចិន្ត្រៃយ៍។"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"កូដ PIN មិនដូចគ្នា"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ព្យាយាមលំនាំច្រើនពេក"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"អ្នកបានបញ្ចូលកូដ PIN របស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"អ្នកបានបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។\n\nព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_1">%d</xliff:g> វិនាទី។"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ទូរស័ព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"អ្នកបានបញ្ចូលកូដ 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="7813713389422226531">"អ្នកបានបញ្ចូលពាក្យសម្ងាត់មិនត្រឹមត្រូវ <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="74089475965050805">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <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="8774056606869646621">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <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="1843331751334128428">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <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="258925501999698032">"អ្នកបានព្យាយាមដោះសមិនត្រឹមត្រូវលើថេប្លេតនេះ <xliff:g id="NUMBER">%d</xliff:g> ដង។ ថេប្លេតនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ ទូរស័ព្ទនេះនឹងត្រូវបានកំណត់ឡើងវិញ ដែលវានឹងលុបទិន្នន័យរបស់វាទាំងអស់។"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <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="6945823186629369880">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <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_erasing_user" product="tablet" msgid="3963486905355778734">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ អ្នកប្រើនេះនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យអ្នកប្រើទាំងអស់។"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់។"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់។"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <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_profile" product="default" msgid="6853071165802933545">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <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_erasing_profile" product="tablet" msgid="4686386497449912146">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើថេប្លេតរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់របស់អ្នក។"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"អ្នកបានព្យាយាមដោះសោមិនត្រឹមត្រូវលើទូរស័ព្ទរបស់អ្នក <xliff:g id="NUMBER">%d</xliff:g> ដង។ ប្រវត្តិរូបការងាររបស់អ្នកនឹងត្រូវបានដកចេញ ដែលវានឹងលុបទិន្នន័យប្រវត្តិរូបទាំងអស់របស់អ្នក។"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នកបានគូរលំនាំដោះសោមិនត្រឹមត្រូវ <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងមិនជោគជ័យ អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោកុំព្យូទ័របន្ទះរបស់អ្នក ដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%d</xliff:g> ដង អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរស័ព្ទរបស់អ្នកដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%d</xliff:g> វិនាទី។"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"អ្នកបានគូរលំនាំដោះសោមិនត្រឹមត្រូវ <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="1437638152015574839">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <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="30531039455764924">"លេខកូដ PIN ស៊ីមមិនត្រឹមត្រូវ អ្នកត្រូវទាក់ទងក្រុមហ៊ុនបញ្ជូនរបស់អ្នកឥឡូវនេះ ដើម្បីដោះសោឧបករណ៍របស់អ្នក។"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">លេខកូដសម្ងាត់ស៊ីមមិនត្រឹមត្រូវ អ្នកនៅសល់ការព្យាយាម <xliff:g id="NUMBER_1">%d</xliff:g> ដងទៀត</item>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index c3d2a61..3ad18c3 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ಸರಿಯಾದ PUK ಕೋಡ್ ಅನ್ನು ಮರು-ನಮೂದಿಸಿ. ಸತತ ಪ್ರಯತ್ನಗಳು ಸಿಮ್ ಅನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ಪಿನ್ ಕೋಡ್ಗಳು ಹೊಂದಾಣಿಕೆಯಾಗುತ್ತಿಲ್ಲ"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ಹಲವಾರು ಪ್ಯಾಟರ್ನ್ ಪ್ರಯತ್ನಗಳು"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ನಿಮ್ಮ ಪಿನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಟೈಪ್ ಮಾಡಿರುವಿರಿ. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಚಿತ್ರಿಸಿರುವಿರಿ. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ನಿಮ್ಮ ಪಿನ್ ಅನ್ನು ನೀವು <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="7813713389422226531">"ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನೀವು <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="74089475965050805">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <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="8774056606869646621">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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="1843331751334128428">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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="258925501999698032">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಈ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಈ ಫೋನ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲಾಗುತ್ತದೆ, ಇದು ಅದರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಈ ಮೂಲಕ ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಈ ಮೂಲಕ ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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="6945823186629369880">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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_erasing_user" product="tablet" msgid="3963486905355778734">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಈ ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಬಳಕೆದಾರರ ಎಲ್ಲ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಕ್ಕೂ ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ನಂತರ, ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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_profile" product="default" msgid="6853071165802933545">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು <xliff:g id="NUMBER">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಪ್ರಯತ್ನಿಸಿರುವಿರಿ. ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ತೆಗೆದುಹಾಕಲಾಗುತ್ತದೆ, ಇದು ಎಲ್ಲ ಪ್ರೊಫೈಲ್ ಡೇಟಾವನ್ನು ಅಳಿಸುತ್ತದೆ."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <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="1437638152015574839">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <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="30531039455764924">"ಸಿಮ್ ಪಿನ್ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಲು ನೀವು ಈ ಕೂಡಲೇ ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಬೇಕು."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">ಸಿಮ್ ಪಿನ್ ಕೋಡ್ ತಪ್ಪಾಗಿದೆ, ನಿಮ್ಮಲ್ಲಿ <xliff:g id="NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ.</item>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index 691f0a4..a85f03d 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"올바른 PUK 코드를 다시 입력하세요. 입력을 반복해서 시도하면 SIM을 영구적으로 사용할 수 없게 됩니다."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 코드가 일치하지 않음"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"패턴 시도 횟수가 너무 많음"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. \n\n<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 태블릿은 재설정되며 모든 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 휴대전화는 재설정되며 모든 데이터가 삭제됩니다."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"비밀번호를 <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="74089475965050805">"잠금해제 패턴을 <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="8774056606869646621">"태블릿 잠금 해제에 <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="1843331751334128428">"휴대전화 잠금 해제에 <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="258925501999698032">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 이 태블릿은 재설정되며 모든 데이터가 삭제됩니다."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 이 휴대전화는 재설정되며 모든 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"태블릿 잠금 해제에 <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="6945823186629369880">"휴대전화 잠금 해제에 <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_erasing_user" product="tablet" msgid="3963486905355778734">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 이 사용자는 삭제되며 모든 사용자 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"태블릿 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 직장 프로필이 삭제되고 모든 프로필 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"휴대전화 잠금 해제에 <xliff:g id="NUMBER_0">%d</xliff:g>번 실패했습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 실패하면 직장 프로필이 삭제되고 모든 프로필 데이터가 삭제됩니다."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"태블릿 잠금 해제에 <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_profile" product="default" msgid="6853071165802933545">"휴대전화 잠금 해제에 <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_erasing_profile" product="tablet" msgid="4686386497449912146">"태블릿 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필이 삭제되며 모든 프로필 데이터가 삭제됩니다."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"휴대전화 잠금 해제에 <xliff:g id="NUMBER">%d</xliff:g>번 실패했습니다. 직장 프로필이 삭제되며 모든 프로필 데이터가 삭제됩니다."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <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="1437638152015574839">"잠금해제 패턴을 <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="30531039455764924">"SIM PIN 코드가 잘못되었습니다. 이동통신사에 문의하여 기기를 잠금 해제해야 합니다."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN 코드가 잘못되었습니다. <xliff:g id="NUMBER_1">%d</xliff:g>번 더 시도할 수 있습니다.</item>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index fb5fbae..6e6394e 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Туура PUK-кодду кайрадан териңиз. Кайталанган аракеттер SIM-картаны биротоло жараксыз кылат."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коддор туура келбеди"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Өтө көп үлгү киргизүү аракети болду"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Сиз PIN-кодуңузду <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Сиз сырсөзүңүздү <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес тердиңиз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> секундадан кийин кайталаңыз."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Сиз 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="7813713389422226531">"Сиз сырсөзүңүздү <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="74089475965050805">"Сиз бөгөттөн чыгаруу үлгүсүн <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="8774056606869646621">"Планшеттин кулпусун ачууда <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="1843331751334128428">"Телефондун кулпусун ачууда <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="258925501999698032">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Бул планшет баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Телефондун кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Бул телефон баштапкы абалга келтирилип, андагы бардык дайындар жок болот."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Планшеттин кулпусун ачууда <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="6945823186629369880">"Телефондун кулпусун ачууда <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_erasing_user" product="tablet" msgid="3963486905355778734">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Телефондун кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Бул колдонуучу чыгарылып салынып, колдонуучунун бардык дайындары жок болот."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Планшетиңиздин кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, жумуш профилиңиз чыгарылып салынып, профилдин бардык дайындары жок болот."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Телефондун кулпусун ачууда <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> жолу туура эмес аракет кылсаңыз, жумуш профилиңиз чыгарылып салынып, профилдин бардык дайындары жок болот."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Планшетиңиздин кулпусун ачууда <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_profile" product="default" msgid="6853071165802933545">"Телефондун кулпусун ачууда <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Планшеттин кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Телефондун кулпусун ачууда <xliff:g id="NUMBER">%d</xliff:g> жолу туура эмес аракет кылдыңыз. Жумуш профили чыгарылып салынып, андагы бардык дайындар жок болот."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, планшетиңизди эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Сиз бөгөттөн чыгаруу үлгүсүн <xliff:g id="NUMBER_0">%d</xliff:g> жолу туура эмес көрсөттүңүз. Дагы <xliff:g id="NUMBER_1">%d</xliff:g> ийгиликсиз аракеттен кийин, телефонуңузду эмейл эсебиңиз аркылуу бөгөттөн чыгаруу талап кылынат.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундадан кийин кайра аракеттениңиз."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Сиз бөгөттөн чыгаруу үлгүсүн <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="1437638152015574839">"Сиз бөгөттөн чыгаруу үлгүсүн <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="30531039455764924">"SIM-карта PIN-коду туура эмес. Эми түзмөктү бөгөттөн чыгарыш үчүн операторуңузга кайрылышыңыз керек."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN-коду туура эмес, сизде <xliff:g id="NUMBER_1">%d</xliff:g> аракет калды.</item>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index b9b68692..e92907a 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ປ້ອນລະຫັດ PUK ທີ່ຖືກຕ້ອງຄືນໃໝ່. ການພະຍາຍາມໃສ່ຫຼາຍເທື່ອຈະເຮັດໃຫ້ຊິມກາດໃຊ້ບໍ່ໄດ້ຖາວອນ."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ລະຫັດ PIN ບໍ່ກົງກັນ"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ແຕ້ມຮູບແບບປົດລັອກຫຼາຍເກີນໄປ"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ທ່ານພິມລະຫັດ PIN ຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ທ່ານພິມລະຫັດຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. \n\nກະລຸນາລອງໃໝ່ໃນອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ວິນາທີ."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ທ່ານພິມລະຫັດ 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="7813713389422226531">"ທ່ານພິມລະຫັດຜິດ <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="74089475965050805">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <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="8774056606869646621">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <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="1843331751334128428">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <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="258925501999698032">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ແທັບເລັດນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂທລະສັບນີ້ຈະຖືກຕັ້ງຄ່າໃໝ່, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຂອງມັນ."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <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="6945823186629369880">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <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_erasing_user" product="tablet" msgid="3963486905355778734">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ຜູ້ໃຊ້ນີ້ຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນຜູ້ໃຊ້."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER_0">%d</xliff:g> ຄັ້ງ. ຫຼັງຈາກລອງບໍ່ສຳເລັດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ, ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <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_profile" product="default" msgid="6853071165802933545">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ທ່ານພະຍາຍາມປົດລັອກແທັບເລັດບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ທ່ານພະຍາຍາມປົດລັອກໂທລະສັບບໍ່ຖືກຕ້ອງ <xliff:g id="NUMBER">%d</xliff:g> ຄັ້ງ. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຈະຖືກເອົາອອກໄປ, ເຊິ່ງຈະລຶບທຸກຂໍ້ມູນໂປຣໄຟລ໌."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກແຕ້ມຜິດອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ, ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກແທັບເລັດຂອງທ່ານ ດ້ວຍການເຂົ້າສູ່ລະບົບໂດຍໃຊ້ອີເມວຂອງທ່ານ.\n\n ກະລຸນາລອງໃໝ່ອີກຄັ້ງໃນອີກ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%d</xliff:g> ວິນາທີ."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຜິດ <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="1437638152015574839">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <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="30531039455764924">"ລະຫັດ PIN ຂອງ SIM ບໍ່ຖືກຕ້ອງທ່ານຕ້ອງຕິດຕໍ່ຫາຜູ່ໃຫ້ບໍລິການ ເພື່ອປົດລັອກອຸປະກອນຂອງທ່ານ."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">ລະຫັດ SIM PIN ບໍ່ຖືກຕ້ອງ, ທ່ານຍັງພະຍາຍາມໄດ້ອີກ <xliff:g id="NUMBER_1">%d</xliff:g> ຄັ້ງ.</item>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index d2bed32..e647795 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Pakartotinai įveskite tinkamą PUK kodą. Pakartotinai bandant SIM bus neleidžiama visam laikui."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodai neatitinka"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Per daug atrakinimo piešinių bandymų"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. \n\nBandykite dar kartą po <xliff:g id="NUMBER_1">%d</xliff:g> sek."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. š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="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodą netinkamai įvedėte <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \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="7813713389422226531">"Neteisingai įvedėte slaptažodį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \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="74089475965050805">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. \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="8774056606869646621">"<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ėkming. bandym. š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="1843331751334128428">"<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ėkming. bandym. šis telefonas bus nustatytas iš naujo ir visi jo duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. 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="7154028908459817066">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. 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="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. š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="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"<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ėkming. bandym. š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="6945823186629369880">"<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ėkming. bandym. šis naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Naudotojas bus pašalintas ir visi naudotojo duomenys bus ištrinti."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti planšetinį kompiuterį. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> kart. nesėkmingai bandėte atrakinti telefoną. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"<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ėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<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ėkming. bandym. darbo profilis bus pašalintas ir visi profilio duomenys bus ištrinti."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"<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="4951507352869831265">"<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="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti planšetinį kompiuterį naudodami „Google“ prisijungimo duomenis.\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="1437638152015574839">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\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="30531039455764924">"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="6721575017538162249">
<item quantity="one">Netinkamas SIM kortelės PIN kodas. Liko <xliff:g id="NUMBER_1">%d</xliff:g> bandymas.</item>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 20bfc06..2ce1676 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN kodi neatbilst."</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Pārāk daudz kombinācijas mēģinājumu"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%d</xliff:g> sekundēm."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem š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="1843331751334128428">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem šis tālrunis tiks atiestatīts, kā arī visi tālruņa dati tiks dzēsti."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Jūs nepareizi ievadījāt PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Jūs nepareizi ievadījāt paroli <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_1">%2$d</xliff:g> sekundēm."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem š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="1843331751334128428">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem š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="258925501999698032">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes 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="7154028908459817066">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes 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="6159955099372112688">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem š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="6945823186629369880">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem š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="tablet" msgid="6159955099372112688">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem š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="6945823186629369880">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Šis lietotājs tiks noņemts, kā arī visi lietotāja dati tiks dzēsti."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jūs <xliff:g id="NUMBER_0">%d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt planšetdatoru. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Jūs <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes nesekmīgi mēģinājāt atbloķēt tālruni. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> nesekmīgiem mēģinājumiem darba profils tiks noņemts, kā arī visi profila dati tiks dzēsti."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes 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="4951507352869831265">"Jūs <xliff:g id="NUMBER">%d</xliff:g> reizes 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="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem planšetdators būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundēm."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem 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> sekundēm."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem 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> sekundēm."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index a06d4e4..adbdd70 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно внесете го точниот ПУК код. Повторните обиди трајно ќе ја оневозможат СИМ картичката."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ПИН кодовите не се совпаѓаат"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Премногу обиди со шема"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Погрешно сте го впишале вашиот ПИН <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Погрешно сте ја впишале вашата лозинка <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Погрешно сте ја употребиле вашата шема за отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. \n\nОбидете се повторно за <xliff:g id="NUMBER_1">%d</xliff:g> секунди."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, таблетот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, телефонот ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Погрешно сте го впишале вашиот ПИН <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="7813713389422226531">"Погрешно сте ја впишале вашата лозинка <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="74089475965050805">"Погрешно сте ја употребиле вашата шема за отклучување <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="8774056606869646621">"Неправилно се обидовте да го отклучите таблетот <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="1843331751334128428">"Неправилно се обидовте да го отклучите телефонот <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="258925501999698032">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој таблет ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој телефон ќе се ресетира, со што ќе се избришат сите негови податоци."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, корисникот ќе се отстрани, со што ќе се избришат сите податоци на корисникот."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Неправилно се обидовте да го отклучите таблетот <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="6945823186629369880">"Неправилно се обидовте да го отклучите телефонот <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_erasing_user" product="tablet" msgid="3963486905355778734">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој корисник ќе се отстрани, со што ќе се избришат сите негови податоци."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Овој корисник ќе се отстрани, со што ќе се избришат сите негови податоци."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER_0">%d</xliff:g> пати. По уште <xliff:g id="NUMBER_1">%d</xliff:g> неправилни обиди, работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Неправилно се обидовте да го отклучите таблетот <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_profile" product="default" msgid="6853071165802933545">"Неправилно се обидовте да го отклучите телефонот <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Неправилно се обидовте да го отклучите таблетот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Неправилно се обидовте да го отклучите телефонот <xliff:g id="NUMBER">%d</xliff:g> пати. Работниот профил ќе се отстрани, со што ќе се избришат сите податоци на профилот."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите таблетот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%d</xliff:g> пати. По <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Погрешно сте ја употребиле вашата шема на отклучување <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="1437638152015574839">"Погрешно сте ја употребиле вашата шема на отклучување <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="30531039455764924">"ПИН кодот за СИМ картичката е неточен. Контактирате со вашиот оператор да го отклучи уредот."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Погрешен ПИН-код за СИМ, ви преостанува уште <xliff:g id="NUMBER_1">%d</xliff:g> обид.</item>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index a7d78f5..a528e69 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ശരിയായ PUK കോഡ് വീണ്ടും നൽകുക. ആവർത്തിച്ചുള്ള ശ്രമങ്ങൾ സിം ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കും."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"പിൻ കോഡുകൾ പൊരുത്തപ്പെടുന്നില്ല"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"വളരെയധികം പാറ്റേൺ ശ്രമങ്ങൾ"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"നിങ്ങളുടെ പിൻ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"നിങ്ങളുടെ പാസ്വേഡ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി ടൈപ്പുചെയ്തു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"നിങ്ങളുടെ പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> സെക്കൻഡിനുള്ളിൽ വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ടാബ്ലെറ്റ് പുനഃസജ്ജീകരിക്കുന്നതിനാൽ ഇതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഫോൺ പുനഃസജ്ജീകരിക്കുന്നതിനാൽ ഇതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"നിങ്ങളുടെ പിൻ <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="7813713389422226531">"നിങ്ങളുടെ പാസ്വേഡ് <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="74089475965050805">"നിങ്ങളുടെ പാറ്റേൺ <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="8774056606869646621">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <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="1843331751334128428">"നിങ്ങളുടെ ഫോൺ <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="258925501999698032">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ടാബ്ലെറ്റിനെ പുനഃസജ്ജീകരിക്കുന്നതിനാൽ അതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഫോണിനെ പുനഃസജ്ജീകരിക്കുന്നതിനാൽ അതിന്റെ എല്ലാ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യും, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <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="6945823186629369880">"നിങ്ങളുടെ ഫോൺ <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_erasing_user" product="tablet" msgid="3963486905355778734">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഈ ഉപയോക്താവിനെ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ ഉപയോക്തൃ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g>-ൽ കൂടുതൽ പരാജയപ്പെട്ട ശ്രമങ്ങൾക്കുശേഷം, ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"നിങ്ങളുടെ ടാബ്ലെറ്റ് <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_profile" product="default" msgid="6853071165802933545">"നിങ്ങളുടെ ഫോൺ <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_erasing_profile" product="tablet" msgid="4686386497449912146">"നിങ്ങളുടെ ടാബ്ലറ്റ് <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"നിങ്ങളുടെ ഫോൺ <xliff:g id="NUMBER">%d</xliff:g> തവണ തെറ്റായി അൺലോക്കുചെയ്യാൻ ശ്രമിച്ചു. ഔദ്യോഗിക പ്രൊഫൈൽ നീക്കംചെയ്യുന്നതിനാൽ എല്ലാ പ്രൊഫൈൽ വിവരങ്ങളും ഇല്ലാതാക്കും."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ടാബ്ലെറ്റ് അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <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="1437638152015574839">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <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="30531039455764924">"സിം പിൻ കോഡ് തെറ്റാണ്, നിങ്ങളുടെ ഉപകരണം അൺലോക്കുചെയ്യാൻ ഇപ്പോൾ നിങ്ങളുടെ കാരിയറുമായി ബന്ധപ്പെടണം."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN കോഡ് തെറ്റാണ്, നിങ്ങൾക്ക് <xliff:g id="NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു.</item>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 495076a..1749a71 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Зөв PUK кодыг дахин оруулна уу. Давтан оролдвол SIM нь бүрмөсөн идэвхгүй болгоно."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодууд таарахгүй байна"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Хээ оруулах оролдлого хэт олон"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Та PIN кодоо <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу бичив. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ таблетын тохиргоо дахин шинээр хийгдэх бөгөөд улмаар таблетын дээрх бүх мэдээлэл устах болно."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ утасны тохиргоо дахин шинээр хийгдэх бөгөөд улмаар утсан дээрх бүх мэдээлэл устах болно."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Та 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="7813713389422226531">"Та 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_pattern_attempts_dialog_message" msgid="74089475965050805">"Та тайлах хээг <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="8774056606869646621">"Та таблетын түгжээг тайлах оролдлогыг <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="1843331751334128428">"Та утасны түгжээг тайлах оролдлогыг <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="258925501999698032">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Энэ таблетын тохиргоо дахин шинээр хийгдэх бөгөөд улмаар таблетан дээрх бүх мэдээлэл устах болно."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Энэ утасны тохиргоо дахин шинээр хийгдэх бөгөөд улмаар утсан дээрх бүх мэдээлэл устах болно."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ хэрэглэгч устгагдах бөгөөд энэ нь улмаар хэрэглэгчийн бүх мэдээллийг устгах болно."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл энэ хэрэглэгч устгагдах бөгөөд энэ нь улмаар хэрэглэгчийн бүх мэдээллийг устгах болно."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Та таблетын түгжээг тайлах оролдлогыг <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="6945823186629369880">"Та утасны түгжээг тайлах оролдлогыг <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_erasing_user" product="tablet" msgid="3963486905355778734">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Энэ хэрэглэгч устгагдаж, улмаар хэрэглэгчийн бүх мэдээлэл устах болно."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Энэ хэрэглэгч устгагдаж, улмаар хэрэглэгчийн бүх мэдээлэл устах болно."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл ажлын профайл устгагдах бөгөөд энэ нь улмаар профайлын бүх мэдээллийг устгах болно."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу хийсэн байна. <xliff:g id="NUMBER_1">%d</xliff:g>-с илүү удаа буруу хийвэл ажлын профайл устгагдах бөгөөд энэ нь улмаар профайлын бүх мэдээллийг устгах болно."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Та таблетын түгжээг тайлах оролдлогыг <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_profile" product="default" msgid="6853071165802933545">"Та утасны түгжээг тайлах оролдлогыг <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Та таблетын түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Ажлын профайл устгагдаж, улмаар профайлын бүх мэдээлэл устах болно."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Та утасны түгжээг тайлах оролдлогыг <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оруулсан байна. Ажлын профайл устгагдаж, улмаар профайлын бүх мэдээлэл устах болно."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл акаунт шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <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="1437638152015574839">"Та тайлах хээг <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="30531039455764924">"СИМ ПИН код буруу, та төхөөрөмжийн түгжээг тайлахын тулд оператор компанитай холбоо барих шаардлагатай."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">СИМ-ны ПИН код буруу байна. Та <xliff:g id="NUMBER_1">%d</xliff:g> удаа оролдлого хийх боломжтой байна.</item>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index da9863f..9452fe7 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"योग्य PUK कोड पुन्हा-प्रविष्ट करा. परत प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"पिन कोड जुळत नाहीत"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बरेच नमुना प्रयत्न"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यरितीने काढला आहे. \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"आपण अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा टॅब्लेट चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा टॅब्लेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <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="7813713389422226531">"आपण आपला संकेतशब्द <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="74089475965050805">"आपण आपला अनलॉक नमुना <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="8774056606869646621">"आपण अनलॉक करण्याचा <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="1843331751334128428">"आपण फोन अनलॉक करण्याचा <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="258925501999698032">"आपण टॅब्लेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा टॅब्लेट रीसेट केला जाईल, जो त्याचा सर्व डेटा हटवेल."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"आपण टॅब्लेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"आपण टॅब्लेट अनलॉक करण्याचा <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="6945823186629369880">"आपण फोन अनलॉक करण्याचा <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_erasing_user" product="tablet" msgid="3963486905355778734">"आपण टॅब्लेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. हा वापरकर्ता काढला जाईल, जे सर्व वापरकर्ता डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"आपण टॅब्लेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"आपण टॅब्लेट अनलॉक करण्याचा <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_profile" product="default" msgid="6853071165802933545">"आपण फोन अनलॉक करण्याचा <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_erasing_profile" product="tablet" msgid="4686386497449912146">"आपण टॅब्लेट अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER">%d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. कार्य प्रोफाईल काढले जाईल, जे सर्व प्रोफाईल डेटा हटवेल."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपण आपला अनलॉक नमुना <xliff:g id="NUMBER_0">%d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%d</xliff:g> अयशस्वी प्रयत्नांनंतर, आपल्याला ईमेल खाते वापरून आपला फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपण आपला अनलॉक नमुना <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="1437638152015574839">"आपण आपला अनलॉक नमुना <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="30531039455764924">"सिम पिन कोड चुकीचा आहे आपण आता आपले डिव्हाइस अनलॉक करण्यासाठी आपल्या वाहकाशी संपर्क साधावा."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">सिम पिन चुकीचा आहे, आपल्याकडे <xliff:g id="NUMBER_1">%d</xliff:g> प्रयत्न उर्वरित आहे.</item>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 554aa12..9b68c5c 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Masukkan semula kod PIN yang betul. Percubaan berulang akan melumpuhkan SIM secara kekal."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kod PIN tidak sepadan"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Terlalu banyak percubaan melukis corak"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN yang salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Anda telah menaip kata laluan yang salah sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. \n\nCuba lagi dalam <xliff:g id="NUMBER_1">%d</xliff:g> saat."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, tablet ini akan ditetapkan semula sekali gus memadam semua data."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, telefon ini akan ditetapkan semula sekali gus memadam semua data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Anda telah menaip PIN yang salah 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="7813713389422226531">"Anda telah menaip kata laluan yang salah 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="74089475965050805">"Anda telah tersilap melukis corak buka kunci anda 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="8774056606869646621">"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 memadam semua data."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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 memadam semua data."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Tablet ini akan ditetapkan semula sekali gus memadam semua datanya."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Telefon ini akan ditetapkan semula sekali gus memadam semua datanya."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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 memadam semua data pengguna."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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 memadam semua data pengguna."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Pengguna ini akan dialih keluar sekali gus memadam semua data pengguna."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, profil kerja anda akan dialih keluar sekali gus memadam semua data profil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang gagal, profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, profil kerja anda akan dialih keluar sekali gus memadam semua data profil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Anda telah salah membuka kunci tablet sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gu memadam semua data profil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Anda telah salah membuka kunci telefon sebanyak <xliff:g id="NUMBER">%d</xliff:g> kali. Profil kerja ini akan dialih keluar sekali gus memadam semua data profil."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda.\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="1437638152015574839">"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 tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\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="30531039455764924">"Kod PIN SIM tidak betul, jadi anda harus menghubungi pembawa anda untuk membuka kunci peranti."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Kod PIN SIM salah, anda ada <xliff:g id="NUMBER_1">%d</xliff:g> cubaan lagi.</item>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index 8cb4f32..cb6eb97 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ်ကို ပြန်လည် ရိုက်ထည့်ပါ.။ ထပ်ခါ ထပ်ခါ ကြိုးစားခြင်းသည် ဆင်းမ်ကဒ်ကို အသုံးပြုမရအောင် ဖြစ်နေနိုင်ပါသည်။"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"ပင် နံပါတ် မတူညီပါ"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"မြောက်မြားစွာ ပုံစံဆွဲ သော့ဖွင့်မှု"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"သင် ပင် နံပါတ်ကို အမှားကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ရိုက်ထည့်ပြီးပါပြီ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့် အကြာတွင် ပြန်လည်ကြိုးစားပါ"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"သင်သည် စကားဝှက်ကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် မှားရိုက်ပြီးပါပြီ။ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာ ပြန်လည်ကြိုးစားပါ"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"သင် ပုံစံဆွဲ သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ်မြောက် မအောင်မြင်ပါ။ \n\n<xliff:g id="NUMBER_1">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤတက်ဘလက်အား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"သင် ပင် နံပါတ်ကို အမှားကို <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="7813713389422226531">"သင်သည် စကားဝှက်ကို <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="74089475965050805">"သင် ပုံစံဆွဲ သော့ဖွင့်ခြင်းကို <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="8774056606869646621">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <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="1843331751334128428">"ဖုန်းအား သော့ဖွင့်ရန် သင် <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="258925501999698032">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤဖုန်းအား အစမှပြန်စဖွင့်မည်ဖြစ်ပြီး၊ ၎င်း၏ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ ဤအသုံးပြုသူအား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <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="6945823186629369880">"ဖုန်းအား သော့ဖွင့်ရန် သင် <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_erasing_user" product="tablet" msgid="3963486905355778734">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ ဤအသုံးပြုသူအား ဖယ်ထုတ်မည်ဖြစ်ပြီး၊ အသုံးပြုသူဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER_0">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ <xliff:g id="NUMBER_1">%d</xliff:g> ကြိမ် ကြိုးစားပြီးနောက် မအောင်မြင်ပါက၊ သင့် အလုပ်ပရိုဖိုင်အား ဖယ်ထုတ်ခြင်းခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားပါမည်။"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <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_profile" product="default" msgid="6853071165802933545">"ဖုန်းအား သော့ဖွင့်ရန် သင် <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_erasing_profile" product="tablet" msgid="4686386497449912146">"တက်ဘလက်အား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ဖုန်းအား သော့ဖွင့်ရန် သင် <xliff:g id="NUMBER">%d</xliff:g> ကြိမ် ကြိုးစားရာ မမှန်ကန်ခဲ့ပါ။ အလုပ်ပရိုဖိုင် ဖယ်ထုတ်ခံရမည်ဖြစ်ပြီး၊ ပရိုဖိုင်ဒေတာအားလုံး ပျက်သွားမည်ဖြစ်သည်။"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်တက်ဘလက်အား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <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="1437638152015574839">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <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="30531039455764924">"ဆင်းကဒ် လျှို့ဝှက် အမှတ် မှားယွင်းပါသည်, ဖုန်းလိုင်းဌာနကို ဆက်သွယ်ရမည် ဖြစ်ပါတယ်"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">ဆင်းမ်ကဒ်၏ ပင်နံပါတ် မှားနေပါသည်၊ သင့်တွင်<xliff:g id="NUMBER_1">%d</xliff:g> ခါ ကြိုးစားခွင့် ကျန်ပါသေးသည်။</item>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 248f65d..fabda4b 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Skriv inn den korrekte PUK-koden på nytt. Gjentatte forsøk kommer til å deaktivere SIM-kortet."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-kodene stemmer ikke overens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"For mange forsøk på tegning av mønster"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har oppgitt feil PIN-kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har tastet inn passordet ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har tegnet opplåsningsmønsteret ditt feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. \n\nPrøv på nytt om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, tilbakestilles nettbrettet, noe som vil slette alle nettbrettets data."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, tilbakestilles telefonen, noe som vil slette alle telefonens data."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, tilbakestilles nettbrettet, noe som vil slette alle nettbrettets data."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, tilbakestilles telefonen, noe som vil slette alle telefonens data."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Dette nettbrettet blir nå tilbakestilt, og alle data blir slettet."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne telefonen blir nå tilbakestilt, og alle data blir slettet.."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes brukeren, noe som vil slette alle brukerdata."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne brukeren blir nå fjernet, og alle brukerdata blir slettet."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Denne brukeren blir nå fjernet, og aller brukerdata blir slettet."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter <xliff:g id="NUMBER_1">%2$d</xliff:g> mislykket forsøk til, fjernes arbeidsprofilen, noe som vil slette alle profildata."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Du har gjort feil i forsøket på å låse opp nettbrettet <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Du har gjort feil i forsøket på å låse opp telefonen <xliff:g id="NUMBER">%d</xliff:g> ganger. Arbeidsprofilen blir fjernet, og alle profildata blir slettet."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale 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">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%d</xliff:g> gale 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">%d</xliff:g> sekunder."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale 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="1437638152015574839">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 4a5907e0..2f9cb6e 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"PUK कोड पुन:प्रदान गर्नुहोस्। धेरै पुन:प्रयासहरूले SIMलाई स्थायी रूपमा निष्क्रिय गरिदिने छ।"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN कोडहरू मेल खाएन"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"निकै धेरै ढाँचा कोसिसहरू"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"तपाईँले गलत तरिकाले तपाईँको PIN <xliff:g id="NUMBER_0">%d</xliff:g> पटक टाइप गर्नु भएको छ। \n\n<xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"तपाईँले तपाईँक पासवर्ड <xliff:g id="NUMBER_0">%d</xliff:g> पटक गलत टाइप गर्नुभएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%d</xliff:g> पटक खिच्नु भएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g>पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो ट्याब्लेट रिसेट हुनेछ जसले आफ्नो सम्पूर्ण डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। पछि <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो फोन रिसेट हुनेछ जसले सम्पूर्ण डेटा मेटाउनेछ।।"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"तपाईँले गलत तरिकाले तपाईँको 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="7813713389422226531">"तपाईँले तपाईँक पासवर्ड <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="74089475965050805">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <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="8774056606869646621">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<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="1843331751334128428">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <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="258925501999698032">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। यो ट्याब्लेट रिेसेट गरिनेछ जसले सम्पूर्ण डेटा मेट्नेछ।"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। यो फोन रिसेट गरिनेछ जसले सम्पूर्ण डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले सबै प्रयोगकर्ता डेटा मेट्नेछ।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<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="6945823186629369880">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <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_erasing_user" product="tablet" msgid="3963486905355778734">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ ।"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि , काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<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_profile" product="default" msgid="6853071165802933545">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <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_erasing_profile" product="tablet" msgid="4686386497449912146">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण प्रोफाइल डेटा मेट्नेछ ।"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण प्रोफाइल डेटा मेट्नेछ।"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डहरूमा।"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <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="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <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="30531039455764924">"SIM PIN कोड गलत छ। अब तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दर।"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other"> गलत SIM PIN कोड, तपाईँ सँग <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 35caf77..3960fc2 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%d</xliff:g> seconden."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%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="1843331751334128428">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt deze telefoon gereset, waardoor alle gegevens worden verwijderd."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Je hebt je pincode <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Je hebt je wachtwoord <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getypt. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. \n\nProbeer het opnieuw over <xliff:g id="NUMBER_1">%2$d</xliff:g> seconden."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%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="6945823186629369880">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Je hebt <xliff:g id="NUMBER">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Deze gebruiker wordt verwijderd, waardoor alle gebruikersgegevens worden verwijderd."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de tablet te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Je hebt <xliff:g id="NUMBER_0">%d</xliff:g> mislukte pogingen ondernomen om de telefoon te ontgrendelen. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 het werkprofiel verwijderd, waardoor alle profielgegevens worden verwijderd."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je tablet te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 u 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="1437638152015574839">"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 u 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="30531039455764924">"Onjuiste pincode voor simkaart. U moet nu contact opnemen met je provider om je apparaat te ontgrendelen."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-pa-rIN/strings.xml b/packages/Keyguard/res/values-pa-rIN/strings.xml
index 8486b63..2deed85 100644
--- a/packages/Keyguard/res/values-pa-rIN/strings.xml
+++ b/packages/Keyguard/res/values-pa-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ਲਹੀ PUK ਕੋਡ ਮੁੜ-ਦਰਜ ਕਰੋ। ਦੁਹਰਾਈਆਂ ਗਈਆਂ ਕੋਸ਼ਿਸ਼ਾਂ SIM ਨੂੰ ਸਥਾਈ ਤੌਰ ਤੇ ਅਸਮਰੱਥ ਬਣਾ ਦੇਵੇਗਾ।"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN ਕੋਡ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਪੈਟਰਨ ਕੋਸ਼ਿਸ਼ਾਂ"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ਤੁਸੀਂ ਆਪਣਾ PIN <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਪਾਸਵਰਡ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟਾਈਪ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਟੈਬਲੇਟ ਰੀਸੈਟ ਕੀਤੀ ਜਾਏਗੀ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਹ ਫੋਨ ਰੀਸੈਟ ਕੀਤਾ ਜਾਏਗਾ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ਤੁਸੀਂ ਆਪਣਾ 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="7813713389422226531">"ਤੁਸੀਂ <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="74089475965050805">"ਤੁਸੀਂ <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="8774056606869646621">"ਤੁਸੀਂ <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="1843331751334128428">"ਤੁਸੀਂ <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="258925501999698032">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਇਹ ਟੈਬਲੇਟ ਰੀਸੈਟ ਕੀਤੀ ਜਾਏਗੀ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗੀ।"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਇਹ ਫੋਨ ਰੀਸੈਟ ਕੀਤਾ ਜਾਏਗਾ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਏਗਾ, ਜੋ ਸਾਰਾ ਉਪਭੋਗਤਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਜਾਏਗਾ, ਜੋ ਸਾਰਾ ਉਪਭੋਗਤਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ਤੁਸੀਂ <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="6945823186629369880">"ਤੁਸੀਂ <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_erasing_user" product="tablet" msgid="3963486905355778734">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗੀ।"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਇਹ ਉਪਭੋਗਤਾ ਹਟਾ ਦਿੱਤਾ ਜਾਏਗਾ, ਜੋ ਇਸਦਾ ਸਾਰਾ ਉਪਭੋਗਤਾ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗਾ।"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ਤੁਸੀਂ <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_profile" product="default" msgid="6853071165802933545">"ਤੁਸੀਂ <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਟੈਬਲੇਟ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗੀ।"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ਤੁਸੀਂ <xliff:g id="NUMBER">%d</xliff:g> ਵਾਰ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਫੋਨ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ। ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਹਟਾ ਦਿੱਤੀ ਜਾਏਗੀ, ਜੋ ਸਾਰਾ ਪ੍ਰੋਫਾਈਲ ਡਾਟਾ ਮਿਟਾ ਦੇਵੇਗੀ।"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣੀ ਟੈਬਲੇਟ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਨਲੌਕ ਪੈਟਰਨ ਗ਼ਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫੋਨ ਅਨਲੌਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ਤੁਸੀਂ <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="1437638152015574839">"ਤੁਸੀਂ <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="30531039455764924">"ਗ਼ਲਤ SIM PIN ਕੋਡ, ਹੁਣ ਤੁਹਾਨੂੰ ਆਪਣੀ ਡਿਵਾਈਸ ਨੂੰ ਅਨਲੌਕ ਕਰਨ ਲਈ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰਨਾ ਪਵੇਗਾ।"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">ਗ਼ਲਤ SIM PIN ਕੋਡ, ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ।</item>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 04930c5..53c3d60f 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Ponownie podaj poprawny kod PUK. Nieudane próby spowodują trwałe wyłączenie karty SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kody PIN nie pasują"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Zbyt wiele prób narysowania wzoru"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Wpisałeś nieprawidłowy kod PIN <xliff:g id="NUMBER_0">%d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> wpisałeś nieprawidłowe hasło. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Narysowałeś nieprawidłowy wzór odblokowania <xliff:g id="NUMBER_0">%d</xliff:g> razy. \n\nSpróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Wpisałeś nieprawidłowy kod PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> razy. \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="7813713389422226531">"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="74089475965050805">"Narysowałeś nieprawidłowy wzór odblokowania <xliff:g id="NUMBER_0">%1$d</xliff:g> razy. \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="8774056606869646621">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach tablet zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach telefon zostanie zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Zostanie on zresetowany, co spowoduje skasowanie z niego wszystkich danych."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach, ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach, ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Ten użytkownik zostanie usunięty, co spowoduje skasowanie wszystkich jego danych."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Próbowałeś <xliff:g id="NUMBER_0">%d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować tablet. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Próbowałeś <xliff:g id="NUMBER_0">%1$d</xliff:g> razy nieprawidłowo odblokować telefon. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować tablet. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Próbowałeś <xliff:g id="NUMBER">%d</xliff:g> razy nieprawidłowo odblokować telefon. Profil do pracy zostanie usunięty, co spowoduje skasowanie wszystkich danych tego profilu."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 danych logowania na konto Google.\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="1437638152015574839">"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 danych logowania na konto Google.\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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-pt-rBR/strings.xml b/packages/Keyguard/res/values-pt-rBR/strings.xml
index 0ef07e5..19d1e4a 100644
--- a/packages/Keyguard/res/values-pt-rBR/strings.xml
+++ b/packages/Keyguard/res/values-pt-rBR/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, 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="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, 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="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, 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="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%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">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%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">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index dda689c..5fda4d7 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Volte a introduzir o código PUK correto. Demasiadas tentativas consecutivas irão desativar permanentemente o SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não correspondem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Demasiadas tentativas para desenhar sequência"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu o PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Escreveu a palavra-passe incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Desenhou a sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este telemóvel será reposto, o que eliminará todos os seus dados."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Escreveu 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="7813713389422226531">"Escreveu 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="74089475965050805">"Desenhou a sua sequência 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="8774056606869646621">"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 telemóvel será reposto, o que eliminará todos os seus dados."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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 seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este telemóvel será reposto, o que eliminará todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, este utilizador será removido, o que eliminará todos os dados respetivos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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 respetivos."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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 respetivos."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER">%d</xliff:g> vezes. Este utilizador será removido, o que eliminará todos os dados respetivos."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER">%d</xliff:g> vezes. Este utilizador será removido, o que eliminará todos os dados respetivos."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tentou desbloquear incorretamente o tablet <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Tentou desbloquear incorretamente o telemóvel <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem êxito, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, o perfil de trabalho será removido, o que eliminará todos os dados do perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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 perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"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 perfil."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, 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">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, 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">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, 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="1437638152015574839">"Desenhou a sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 0ef07e5..19d1e4a 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Introduza novamente o código PUK correto. Muitas tentativas malsucedidas desativarão permanentemente o SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Os códigos PIN não coincidem"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Muitas tentativas de padrão"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Você digitou seu PIN incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Você digitou sua senha incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. \n\nTente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este tablet será redefinido, o que excluirá todos os seus dados."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este smartphone será redefinido, o que excluirá todos os seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este tablet será redefinido, o que excluirá todos os seus dados."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este smartphone será redefinido, o que excluirá todos os seus dados."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, 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="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, 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="tablet" msgid="6159955099372112688">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, 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="6945823186629369880">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, este usuário será removido, o que excluirá todos os dados do usuário."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER">%d</xliff:g> vezes. Este usuário será removido, o que excluirá todos os dados do usuário."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Você tentou desbloquear o tablet incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas,o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Você tentou desbloquear o smartphone incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Após mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas malsucedidas, o perfil de trabalho será removido, o que excluirá todos os dados do perfil."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%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">%d</xliff:g> segundos."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%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">%d</xliff:g> segundos."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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="1437638152015574839">"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="30531039455764924">"Código PIN do SIM incorreto. Entre em contato com a operadora para desbloquear o dispositivo."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Código PIN do SIM incorreto. Tentativas restantes: <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index a017564..bded162 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Reintroduceţi codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Codurile PIN nu coincid"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Prea multe încercări de desenare a modelului"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Aţi introdus incorect codul PIN de <xliff:g id="NUMBER_0">%d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Aţi introdus incorect parola de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%d</xliff:g> (de) secunde."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%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="1843331751334128428">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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> (de) secunde."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"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> (de) secunde."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"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> (de) secunde."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%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="6945823186629369880">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ați efectuat <xliff:g id="NUMBER_0">%d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereușite, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%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">%d</xliff:g> (de) secunde."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%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">%d</xliff:g> (de) secunde."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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> (de) secunde."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"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> (de) secunde."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 226f566..713f399 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Введите правильный PUK-код. После нескольких неудачных попыток SIM-карта будет заблокирована."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коды не совпадают"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Слишком много попыток ввода графического ключа"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали PIN-код. \n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали пароль.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ.\n\nПовтор через <xliff:g id="NUMBER_1">%d</xliff:g> сек."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Количество неудачных попыток разблокировать планшетный ПК: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, настройки планшетного ПК будут сброшены, а все его данные – удалены."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, настройки телефона будут сброшены, а все его данные – удалены."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Вы <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="7813713389422226531">"Вы <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="74089475965050805">"Вы <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="8774056606869646621">"Количество неудачных попыток разблокировать планшетный ПК: <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="1843331751334128428">"Количество неудачных попыток разблокировать телефон: <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="258925501999698032">"Достигнуто максимальное количество неудачных попыток разблокировать планшетный ПК (<xliff:g id="NUMBER">%d</xliff:g>). Настройки планшетного ПК будут сброшены, а все его данные – удалены."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Настройки телефона будут сброшены, а все его данные – удалены."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Количество неудачных попыток разблокировать планшетный ПК: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, аккаунт этого пользователя и все его данные будут удалены."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, аккаунт этого пользователя и все его данные будут удалены."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Количество неудачных попыток разблокировать планшетный ПК: <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="6945823186629369880">"Количество неудачных попыток разблокировать телефон: <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_erasing_user" product="tablet" msgid="3963486905355778734">"Достигнуто максимальное количество неудачных попыток разблокировать планшетный ПК (<xliff:g id="NUMBER">%d</xliff:g>). Аккаунт этого пользователя и все его данные будут удалены."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Аккаунт этого пользователя и все его данные будут удалены."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Количество неудачных попыток разблокировать планшетный ПК: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, рабочий профиль и все его данные будут удалены."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Количество неудачных попыток разблокировать телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Количество оставшихся попыток: <xliff:g id="NUMBER_1">%d</xliff:g>. Если они также будут неуспешными, рабочий профиль и все его данные будут удалены."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Количество неудачных попыток разблокировать планшетный ПК: <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_profile" product="default" msgid="6853071165802933545">"Количество неудачных попыток разблокировать телефон: <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Достигнуто максимальное количество неудачных попыток разблокировать планшетный ПК (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Достигнуто максимальное количество неудачных попыток разблокировать телефон (<xliff:g id="NUMBER">%d</xliff:g>). Рабочий профиль и все его данные будут удалены."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Неверный PIN-код. Обратитесь к оператору связи, чтобы разблокировать SIM-карту."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Неверный PIN-код. Осталась <xliff:g id="NUMBER_1">%d</xliff:g> попытка. После этого SIM-карта будет заблокирована и вам придется обратиться к оператору связи.</item>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 0afda24..4ec025a 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"නිවැරදි PUK කේතය නැවත ඇතුලත් කරන්න. නැවත නැවත උත්සාහ කිරීමෙන් SIM එක ස්ථිරවම අබල කරයි."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN කේත ගැලපී නැත"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"රටා උත්සාහ කිරීම් වැඩිය"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ඔබ PIN අංකය <xliff:g id="NUMBER_0">%d</xliff:g> වාරයක් වැරදියට ටයිප් කොට ඇත.\n\n තත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ මුරපදය ඔබ වැරදියට ටයිප් කර ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ට පසුව නැවත උත්සහ කරන්න."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"ඔබ <xliff:g id="NUMBER_0">%d</xliff:g> වාරයක් අගුළු ඇරීමේ රටාව වැරදියට ඇඳ ඇත. \n\nතත්පර <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඇතුළත නැවත උත්සාහ කරන්න."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, ටැබ්ලටය නැවත සකස් කෙරෙනු ඇති අතර, එමගින් සියලු දත්ත මකා දැමෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, දුරකථනය නැවත සකස් කෙරෙනු ඇති අතර, එමගින් සියලු දත්ත මකා දැමෙනු ඇත."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"ඔබ 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="7813713389422226531">"<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="74089475965050805">"ඔබ <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="8774056606869646621">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <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="1843331751334128428">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <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="258925501999698032">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම දත්ත මකා දමමින්, මෙම ටැබ්ලටය නැවත සැකසෙනු ඇත."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම දත්ත මකා දමමින්, මෙම දුරකථනය නැවත සැකසෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, පරිශීලකයා ඉවත් වනු ඇති අතර, එමගින් සියලු පරිශීලක දත්ත මකා දැමෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, පරිශීලකයා ඉවත් වනු ඇති අතර, එමගින් සියලු පරිශීලක දත්ත මකා දැමෙනු ඇත."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <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="6945823186629369880">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <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_erasing_user" product="tablet" msgid="3963486905355778734">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පරිශීලක දත්ත මකා දමමින්, මෙම පරිශීලකයා මකා දැමෙනු ඇත."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පරිශීලක දත්ත මකා දමමින්, මෙම පරිශීලකයා මකා දැමෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, කාර්යාල පැතිකඩ ඉවත් වනු ඇති අතර, එමගින් සියලු පැතිකඩ දත්ත මකා දැමෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER_0">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, කාර්යාල පැතිකඩ ඉවත් වනු ඇති අතර, එමගින් සියලු පැතිකඩ දත්ත මකා දැමෙනු ඇත."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <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_profile" product="default" msgid="6853071165802933545">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <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_erasing_profile" product="tablet" msgid="4686386497449912146">"ඔබ ඔබගේ ටැබ්ලටය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පැතිකඩ දත්ත මකා දමමින්, කාර්යාල පැතිකඩ මකා දැමෙනු ඇත."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"ඔබ ඔබගේ දුරකථනය අගුළු හැරීමට <xliff:g id="NUMBER">%d</xliff:g> වරක් වැරදි වශයෙන් උත්සාහ කර ඇත. සියලුම පැතිකඩ දත්ත මකා දමමින්, කාර්යාල පැතිකඩ මකා දැමෙනු ඇත."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ඔබ අගුළු ඇරිමේ රටාව <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් වැරදියට ඇඳ ඇත. තවත් අසාර්ථක උත්සාහ <xliff:g id="NUMBER_1">%d</xliff:g> කින් පසුව, ඊ-තැපැල් ගිණුම භාවිතා කරමින් ඔබගේ ටැබ්ලටයේ අගුළු ඇරීමට ඔබට පවසනු ඇත.\n\n නැවත තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> කින් උත්සාහ කරන්න."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ඔබ අගුළු ඇරිමේ රටාව <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="1437638152015574839">"ඔබ වැරදියට <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="30531039455764924">"වැරදී SIM PIN කේතයකි, ඔබගේ දුරකතනයේ අඟුල හැරීමට ඔබගේ වාහකයා ඔබ දැන් සම්බන්ධ කරගත යුතුය."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">වැරදි SIM PIN කේතයකි, ඔබට උත්සාහයන් <xliff:g id="NUMBER_1">%d</xliff:g> ක් ඉතිරිව ඇත.</item>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 4825e4a..f9470ea 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Kódy PIN sa nezhodujú"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Príliš veľa pokusov o nakreslenie vzoru"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávny kód PIN. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste zadali nesprávne heslo. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste použili nesprávny bezpečnostný vzor. \n\nSkúste to znova o <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%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="1843331751334128428">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"<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="7813713389422226531">"<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="74089475965050805">"<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="8774056606869646621">"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 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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%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="6945823186629369880">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tablet ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Používateľ bude odstránený a spolu s ním všetky jeho údaje."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefón ste sa pokúsili <xliff:g id="NUMBER">%d</xliff:g>-krát nesprávne odomknúť. Používateľ bude odstránený a spolu s ním všetky jeho údaje."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablet ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefón ste sa pokúsili <xliff:g id="NUMBER_0">%d</xliff:g>-krát nesprávne odomknúť. Po ďalších neúspešných pokusoch (počet: <xliff:g id="NUMBER_1">%d</xliff:g>) bude pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 pracovný profil odstránený a spolu s ním všetky údaje profilu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%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">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%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">%d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste 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="1437638152015574839">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index 41dde2c..1807bd8f 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Vnovič vnesite pravilno kodo PUK. Večkratni poskusi bodo trajno onemogočili kartico SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Kodi PIN se ne ujemata"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Preveč poskusov vzorca"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%d</xliff:g>-krat. \n\nPoskusite znova čez <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ponastavljen, zaradi česar bodo izbrisani vsi podatki v njem."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Geslo ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat vnesli napačno. \n\nZnova poskusite čez <xliff:g id="NUMBER_1">%2$d</xliff:g> s."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Vzorec za odklepanje ste nepravilno narisali <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat. \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="8774056606869646621">"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, zaradi česar bodo izbrisani vsi podatki v njem."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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, zaradi česar bodo izbrisani vsi podatki v njem."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo ta uporabnik odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Ta uporabnik bo odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Ta uporabnik bo odstranjen, zaradi česar bodo izbrisani vsi podatki uporabnika."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Če ga neuspešno poskusite odkleniti še <xliff:g id="NUMBER_1">%d</xliff:g>-krat, bo delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 delovni profil odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Tablični računalnik ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Telefon ste neuspešno poskusili odkleniti <xliff:g id="NUMBER">%d</xliff:g>-krat. Delovni profil bo odstranjen, zaradi česar bodo izbrisani vsi podatki profila."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-sq-rAL/strings.xml b/packages/Keyguard/res/values-sq-rAL/strings.xml
index 31ed223..3b34db5 100644
--- a/packages/Keyguard/res/values-sq-rAL/strings.xml
+++ b/packages/Keyguard/res/values-sq-rAL/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Kodet PIN nuk përputhen"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Shumë tentativa për motivin"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"E ke shkruar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht PIN-in tënd.\n\n Provo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"E ke shkruar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht fjalëkalimin.\n\nProvo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për të vizatuar motivin tënd. \n\nProvo sërish për <xliff:g id="NUMBER_1">%d</xliff:g> sekonda."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, tableti do të rivendoset si në gjendjen e fabrikës dhe kjo do t\'i fshijë të gjitha të dhënat."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë gabimisht për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> përpjekjeve të tjera të pasuksesshme, telefoni do të rivendoset dhe të gjitha të dhënat do të fshihen."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"E ke shkruar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë gabimisht PIN-in tënd.\n\n Provo 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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, tableti do të rivendoset si në gjendjen e fabrikës dhe kjo do t\'i fshijë të gjitha të dhënat."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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 dhe të gjitha të dhënat do të fshihen."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin tënd. Ky tablet do të rivendoset dhe të gjitha të dhënat në të, do të fshihen."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin tënd. Ky telefon do të rivendoset dhe të gjitha të dhënat në të, do të fshihen."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%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="6945823186629369880">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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_now_erasing_user" product="tablet" msgid="3963486905355778734">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Ky përdorues do të hiqet dhe kjo do t fshijë të gjitha të dhënat e përdoruesit."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Ke tentuar <xliff:g id="NUMBER">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Ky përdorues do të hiqet dhe kjo do t\'i fshijë të gjitha të dhënat e përdoruesit."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Ke tentuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses për ta shkyçur telefonin. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Ke tentuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses për ta shkyçur tabletin. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, profili i punës do të hiqet dhe të gjitha të dhënat në të do të fshihen."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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 të gjitha të dhënat në të, do të fshihen."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"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 të gjitha të dhënat në të, do të fshihen."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"E ke vizatuar gabimisht motivin tënd të shkyçjes <xliff:g id="NUMBER_0">%d</xliff:g> herë. Pas <xliff:g id="NUMBER_1">%d</xliff:g> tentativave të tjera të pasuksesshme do të të kërkohet ta shkyçësh tabletin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%d</xliff:g> sekonda."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ke vizatuar <xliff:g id="NUMBER_0">%d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%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">%d</xliff:g> sekonda."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"E ke vizatuar gabimisht motivin tënd të shkyçjes <xliff:g id="NUMBER_0">%1$d</xliff:g> herë. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme do të të kërkohet 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="1437638152015574839">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. 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="30531039455764924">"PIN-i i kartës SIM është i pasaktë. Tani duhet të kontaktosh operatorin për ta shkyçur pajisjen tënde."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">PIN-i 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/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index feb18be..6e311e9 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Поново унесите исправни PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се таблет ресетује и сви подаци са њега бришу."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се телефон ресетује и сви подаци са њега бришу."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни 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="7813713389422226531">"Унели сте нетачну лозинку <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="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <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="8774056606869646621">"Погрешно сте покушали да откључате таблет <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="1843331751334128428">"Погрешно сте покушали да откључате телефон <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="258925501999698032">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пут(а). Таблет ће бити ресетован и сви подаци са њега ће бити избрисани."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Телефон ће бити ресетован и сви подаци са њега ће бити избрисани."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се овај корисник уклања и сви подаци корисника бришу."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се овај корисник уклања и сви подаци корисника бришу."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Погрешно сте покушали да откључате таблет <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="6945823186629369880">"Погрешно сте покушали да откључате телефон <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_erasing_user" product="tablet" msgid="3963486905355778734">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пут(а). Овај корисник ће бити уклоњен и сви подаци корисника ће бити избрисани."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Овај корисник ће бити уклоњен и сви подаци корисника ће бити избрисани."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се пословни профил уклања и сви подаци са профила бришу."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај(а), након чега се пословни профил уклања и сви подаци са профила бришу."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Погрешно сте покушали да откључате таблет <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_profile" product="default" msgid="6853071165802933545">"Погрешно сте покушали да откључате телефон <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <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="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <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="30531039455764924">"Нетачан SIM PIN кôд. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 28bcf98..19afea3 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Ange rätt PUK-kod igen. Om försöken upprepas inaktiveras SIM-kortet permanent."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-koderna stämmer inte överens"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"För många försök med grafiskt lösenord"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. \n\nFörsök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till återställs surfplattan och all data raderas."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till återställs mobilen och all data raderas."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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_password_attempts_dialog_message" msgid="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till återställs surfplattan och all data raderas."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till återställs mobilen och all data raderas."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas användaren bort och all användardata raderas."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Användaren tas bort och all användardata raderas."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER">%d</xliff:g> gånger. Användaren tas bort och all användardata raderas."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Du har försökt låsa upp surfplattan på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Du har försökt låsa upp mobilen på ett felaktigt sätt <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 <xliff:g id="NUMBER_1">%2$d</xliff:g> misslyckade försök till tas jobbprofilen bort och all profildata raderas."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 ombeds du låsa upp surfplattan med 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="1437638152015574839">"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 ombeds 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="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index bd8c68e..2f2c9d8 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Ingiza upya msimbo sahihi wa PUK. Majaribio yanayorudiwa yatalemaza SIM kabisa."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Misimbo ya PIN haifanani"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Majaribio mengi mno ya mchoro"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Umeingiza nenosiri lako kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa mara <xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_1">%d</xliff:g>."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%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="1843331751334128428">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, simu hii itawekwa upya, hatua itakayofuta data yake yote."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Umeingiza nenosiri lako kwa makosa 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="7813713389422226531">"Umeingiza nenosiri lako kwa makosa 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="74089475965050805">"Umechora ruwaza yako ya kufunga kwa makosa 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="8774056606869646621">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <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="1843331751334128428">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, simu hii itawekwa upya, hatua itakayofuta data yake yote."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. 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="7154028908459817066">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. 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="6159955099372112688">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. Mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Mtumiaji huyu ataondolewa, hatua itakayofuta data yote ya mtumiaji."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Ukikosea majaribio mengine <xliff:g id="NUMBER_1">%2$d</xliff:g>, wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Umekosea majaribio ya kufungua kompyuta kibao mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Umekosea majaribio ya kufungua simu mara <xliff:g id="NUMBER">%d</xliff:g>. Wasifu wa kazini utaondolewa, hatua itakayofuta data yote ya wasifu."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo kwa kutumia akaunti yako ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%d</xliff:g>."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Umekosea katika kuweka mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> bila kufaulu, utaombwa kufungua kompyuta yako ndogo 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="1437638152015574839">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, 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="30531039455764924">"Msimbo wa PIN ya SIM usiosahihi sasa lazima uwasiliane na mtoa huduma wako ili ufungue kifaa chako."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">Msimbo wa PIN ya SIM si sahihi, umebakisha majaribio <xliff:g id="NUMBER_1">%d</xliff:g>.</item>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 32c93b0..869c867 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"சரியான PUK குறியீட்டை மீண்டும் உள்ளிடவும். தொடர் முயற்சிகள் சிம் ஐ நிரந்தரமாக முடக்கிவிடும்."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"பின் குறியீடுகள் பொருந்தவில்லை"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"அதிகமான வடிவ முயற்சிகள்"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"உங்கள் கடவுச்சொல்லை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக உள்ளிட்டீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். \n\n<xliff:g id="NUMBER_1">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால், டேப்லெட் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் மொபைல் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"உங்கள் பின்னை <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="7813713389422226531">"உங்கள் கடவுச்சொல்லை <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="74089475965050805">"திறப்பதற்கான வடிவத்தை <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="8774056606869646621">"டேப்லெட்டைத் திறக்க, <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="1843331751334128428">"மொபைலைத் திறக்க, <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="258925501999698032">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். டேப்லெட் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். மொபைல் மீட்டமைக்கப்படும், அத்துடன் இதன் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் இந்தப் பயனர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"மொபைலைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் இந்தப் பயனர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"டேப்லெட்டைத் திறக்க, <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="6945823186629369880">"மொபைலைத் திறக்க, <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_erasing_user" product="tablet" msgid="3963486905355778734">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இவர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இவர் அகற்றப்படுவார், அத்துடன் அவரின் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால், பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"மொபைலைத் திறக்க <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். இன்னும் <xliff:g id="NUMBER_1">%d</xliff:g> முறை தவறாக முயற்சித்தால் பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"டேப்லெட்டைத் திறக்க, <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_profile" product="default" msgid="6853071165802933545">"மொபைலைத் திறக்க <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_erasing_profile" product="tablet" msgid="4686386497449912146">"டேப்லெட்டைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"மொபைலைத் திறக்க, <xliff:g id="NUMBER">%d</xliff:g> முறை தவறாக முயற்சித்துள்ளீர்கள். பணி சுயவிவரம் அகற்றப்படும், அத்துடன் சுயவிவரத்தின் எல்லா தரவும் நீக்கப்படும்."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் டேப்லெட்டைத் திறக்க கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகளில் மீண்டும் முயற்சிக்கவும்."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"திறப்பதற்கான வடிவத்தை <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="1437638152015574839">"திறப்பதற்கான வடிவத்தை <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="30531039455764924">"சிம் பின் குறியீடு தவறானது, உங்கள் சாதனத்தின் தடையை நீக்க, உங்கள் மொபைல் நிறுவனத்தைத் தொடர்புகொள்ள வேண்டும்."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">சிம்மின் பின் குறியீடு தவறானது, உங்களிடம் <xliff:g id="NUMBER_1">%d</xliff:g> முயற்சிகள் மீதமுள்ளன.</item>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index e27f5a9..6513648 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"సరైన PUK కోడ్ను మళ్లీ నమోదు చేయండి. పునరావృత ప్రయత్నాల వలన సిమ్ శాశ్వతంగా నిలిపివేయబడుతుంది."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"పిన్ కోడ్లు సరిపోలలేదు"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"చాలా ఎక్కువ నమూనా ప్రయత్నాలు చేసారు"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"మీరు మీ పిన్ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"మీరు మీ పాస్వర్డ్ను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా టైప్ చేసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ ఫోన్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"మీరు మీ పిన్ను <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="7813713389422226531">"మీరు మీ పాస్వర్డ్ను <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="74089475965050805">"మీరు మీ అన్లాక్ నమూనాను <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="8774056606869646621">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <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="1843331751334128428">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <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="258925501999698032">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. ఈ టాబ్లెట్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. ఈ ఫోన్ రీసెట్ చేయబడుతుంది, ఇందువల్ల ఇందులోని మొత్తం డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <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="6945823186629369880">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <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_erasing_user" product="tablet" msgid="3963486905355778734">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. ఈ వినియోగదారు తీసివేయబడతారు, ఇందువల్ల మొత్తం వినియోగదారు డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు విఫలమైతే, కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <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_profile" product="default" msgid="6853071165802933545">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <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_erasing_profile" product="tablet" msgid="4686386497449912146">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు చెల్లని ప్రయత్నాలు చేశారు. కార్యాలయ ప్రొఫైల్ తీసివేయబడుతుంది, ఇందువల్ల మొత్తం ప్రొఫైల్ డేటా తొలగించబడుతుంది."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ టాబ్లెట్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"మీరు మీ అన్లాక్ నమూనాను <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="1437638152015574839">"మీరు మీ అన్లాక్ నమూనాను <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="30531039455764924">"సిమ్ పిన్ కోడ్ చెల్లదు, మీరు ఇప్పుడు మీ పరికరాన్ని అన్లాక్ చేయడానికి తప్పనిసరిగా మీ క్యారియర్ను సంప్రదించండి."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN కోడ్ చెల్లదు, మీకు <xliff:g id="NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి.</item>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 2629bfd..71d108c 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"ใส่รหัส PUK ที่ถูกต้องอีกครั้ง การพยายามซ้ำหลายครั้งจะทำให้ซิมการ์ดถูกปิดใช้งานอย่างถาวร"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"รหัส PIN ไม่ตรง"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"ลองหลายรูปแบบมากเกินไป"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ PIN ไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว \n\nโปรดลองอีกครั้งใน <xliff:g id="NUMBER_1">%d</xliff:g> วินาที"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"คุณพิมพ์ 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="7813713389422226531">"คุณพิมพ์รหัสผ่านไม่ถูกต้องไป <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="74089475965050805">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้องไป <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="8774056606869646621">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <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="1843331751334128428">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <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="258925501999698032">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตแท็บเล็ตเครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะรีเซ็ตโทรศัพท์เครื่องนี้ ซึ่งจะเป็นการลบข้อมูลทั้งหมดในเครื่อง"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <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="6945823186629369880">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <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_erasing_user" product="tablet" msgid="3963486905355778734">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำผู้ใช้รายนี้ออก ซึ่งจะเป็นการลบข้อมูลผู้ใช้ทั้งหมด"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้ง หากพยายามไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <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_profile" product="default" msgid="6853071165802933545">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <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_erasing_profile" product="tablet" msgid="4686386497449912146">"คุณปลดล็อกแท็บเล็ตไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"คุณปลดล็อกโทรศัพท์ไม่ถูกต้อง <xliff:g id="NUMBER">%d</xliff:g> ครั้ง ระบบจะนำโปรไฟล์งานออก ซึ่งจะเป็นการลบข้อมูลโปรไฟล์ทั้งหมด"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล\n\n โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <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="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <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="30531039455764924">"รหัส PIN ของซิมไม่ถูกต้อง ตอนนี้คุณต้องติดต่อผู้ให้บริการเพื่อปลดล็อกอุปกรณ์ของคุณ"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">รหัส PIN ของซิมไม่ถูกต้อง คุณพยายามได้อีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง</item>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 8bfc6a6..433fdbf 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Muling ilagay ang tamang PUK code. Permanenteng hindi pagaganahin ang SIM ng mga paulit-ulit na pagtatangka."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Hindi tumutugma ang mga PIN code"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Masyadong maraming pagtatangka sa pattern"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama ang iyong PIN nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Na-type mo nang hindi tama ang iyong password nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. \n\nSubukang muli sa loob ng <xliff:g id="NUMBER_1">%d</xliff:g> (na) segundo."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%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="1843331751334128428">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Na-type mo nang hindi tama 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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"<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="1843331751334128428">"<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="258925501999698032">"<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="7154028908459817066">"<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="6159955099372112688">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%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="6945823186629369880">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"<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="6945823186629369880">"<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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Aalisin ang user na ito, na magiging dahilan upang ma-delete ang lahat ng data ng user."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"<xliff:g id="NUMBER">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling password. 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_profile" product="tablet" msgid="4621778507387853694">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang tablet gamit ang maling password. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, 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_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling passowrd. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagsubok, 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_erase_profile" product="tablet" msgid="4621778507387853694">"<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 profile sa trabaho, na magiging dahilan upang ma-delete ang lahat ng data sa profile."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"<xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses mo nang sinubukang i-unlock ang telepono gamit ang maling passowrd. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagsubok, 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="tablet" msgid="4686386497449912146">"<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="4951507352869831265">"<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="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, 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">%d</xliff:g> (na) segundo."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, 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">%d</xliff:g> (na) segundo."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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 pagtatangka, 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="1437638152015574839">"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 pagtatangka, 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="30531039455764924">"Maling PIN code ng SIM, dapat ka nang makipag-ugnay sa iyong carrier upang i-unlock ang iyong device."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Maling PIN code ng SIM, mayroon kang <xliff:g id="NUMBER_1">%d</xliff:g> natitirang pagsubok.</item>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 1e8a589a..c9649d5 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN kodları eşleşmiyor"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Çok fazla sayıda desen denemesi yapıldı"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN kodunuzu <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış yazdınız. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde tekrar deneyin."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%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="1843331751334128428">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"Ş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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%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="6945823186629369880">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Tabletin kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Telefonun kilidini <xliff:g id="NUMBER">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. Bu kullanıcı kaldırılacak ve tüm kullanıcı verileri silinecektir."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Tabletin kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Telefonun kilidini <xliff:g id="NUMBER_0">%d</xliff:g> kez hatalı bir şekilde açmayı denediniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız deneme daha yaparsanız iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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 iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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 iş profili kaldırılacak ve tüm profil verileri silinecektir."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"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, tabletinizi bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"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 telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<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/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index dba0f6c..e4b0e1f 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Повторно введіть правильний PUK-код. Численні спроби назавжди вимкнуть SIM-карту."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN-коди не збігаються"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Забагато спроб намалювати ключ"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"PIN-код неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Пароль неправильно введено стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. \n\nПовторіть спробу через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g> У разі невдачі буде скинуто налаштування планшета й видалено всі його дані."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g> У разі невдачі буде скинуто налаштування телефона й видалено всі його дані."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"Пароль неправильно введено стільки разів: <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="74089475965050805">"Ключ розблокування неправильно намальовано стільки разів: <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="8774056606869646621">"Кількість невдалих спроб розблокувати планшет: <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="1843331751334128428">"Кількість невдалих спроб розблокувати телефон: <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="258925501999698032">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього планшета й видалено всі його дані."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде скинуто налаштування цього телефона й видалено всі його дані."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено цього користувача й усі його дані."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"Кількість невдалих спроб розблокувати планшет: <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="6945823186629369880">"Кількість невдалих спроб розблокувати телефон: <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_erasing_user" product="tablet" msgid="3963486905355778734">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено цього користувача й усі його дані."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено цього користувача й усі його дані."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено робочий профіль і всі його дані."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER_0">%d</xliff:g>. Залишилося спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі буде видалено робочий профіль і всі його дані."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Кількість невдалих спроб розблокувати планшет: <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_profile" product="default" msgid="6853071165802933545">"Кількість невдалих спроб розблокувати телефон: <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_erasing_profile" product="tablet" msgid="4686386497449912146">"Кількість невдалих спроб розблокувати планшет: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Кількість невдалих спроб розблокувати телефон: <xliff:g id="NUMBER">%d</xliff:g>. Буде видалено робочий профіль і всі його дані."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <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="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <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="30531039455764924">"Неправильний PIN-код SIM-карти. Зв’яжіться зі своїм оператором, щоб розблокувати пристрій."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Неправильний PIN-код SIM-карти. У вас залишилась <xliff:g id="NUMBER_1">%d</xliff:g> спроба.</item>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index b6a993b..3a041f5 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"صحیح PUK کوڈ دوبارہ درج کریں۔ بار بار کی کوششیں SIM کو مستقل طور پر غیر فعال کر دیں گی۔"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN کوڈز مماثل نہیں ہیں"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"پیٹرن کی بہت ساری کوششیں"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"آپ نے <xliff:g id="NUMBER_0">%d</xliff:g> بار اپنا PIN غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"آپ نے اپنا پاس ورڈ <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ٹائپ کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ \n\n <xliff:g id="NUMBER_1">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"آپ نے <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="7813713389422226531">"آپ نے اپنا پاس ورڈ <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="74089475965050805">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <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="8774056606869646621">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <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="1843331751334128428">"آپ نے فون کو غیر مقفل کرنے کیلئے <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="258925501999698032">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس ٹیبلیٹ کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس فون کو دوبارہ ترتیب دے دیا جائے گا، جس سے اس کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <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="6945823186629369880">"آپ نے فون کو غیر مقفل کرنے کیلئے <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_erasing_user" product="tablet" msgid="3963486905355778734">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ اس صارف کو ہٹا دیا جائے گا، جس سے صارف کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <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_profile" product="default" msgid="6853071165802933545">"آپ نے فون کو غیر مقفل کرنے کیلئے <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_erasing_profile" product="tablet" msgid="4686386497449912146">"آپ نے ٹیبلیٹ کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"آپ نے فون کو غیر مقفل کرنے کیلئے <xliff:g id="NUMBER">%d</xliff:g> بار غلط طریقے سے کوشش کی ہے۔ دفتری پروفائل ہٹا دیا جائے گا، جس سے پروفائل کا سبھی ڈیٹا حذف ہو جائے گا۔"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا ٹیبلیٹ غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <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="1437638152015574839">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <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="30531039455764924">"غلط SIM PIN کوڈ اب آپ کو اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کرنا چاہئے۔"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">غلط SIM PIN کوڈ، آپ کے پاس <xliff:g id="NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔</item>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index eae5ff8..44d5b50 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"PIN-kod mos kelmadi"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Chizmali parolni ochishga juda ko‘p urinildi"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Siz PIN-kodni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Siz parolni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%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="1843331751334128428">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Siz PIN-kodni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Siz parolni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> soniyadan so‘ng qayta urinib ko‘ring."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%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="6945823186629369880">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Endi, ushbu foydalanuvchi o‘chirib tashlanadi va undagi barcha foydalanuvchi ma’lumotlari ham o‘chib ketadi."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Siz planshetni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Siz telefonni qulfdan chiqarish uchun <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri urinish qildingiz. Agar yana <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinish qilsangiz, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, ishchi profil o‘chirib tashlanadi va undagi barcha profil ma’lumotlari ham o‘chib ketadi."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri kiritdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, planshet qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz chizmali kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM karta PIN kodi noto‘g‘ri. Qurilma qulfini ochish uchun aloqa operatoringiz bilan bog‘laning."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 0568998..8d72cd1 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"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="7003469261464593516">"Mã PIN không khớp"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Quá nhiều lần nhập hình"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mã PIN. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần nhập sai mật khẩu. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa. \n\nHãy thử lại sau <xliff:g id="NUMBER_1">%d</xliff:g> giây."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%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="1843331751334128428">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%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_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần nhập sai mã PIN. \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="7813713389422226531">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần nhập sai mật khẩu. \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="74089475965050805">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa. \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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%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="6945823186629369880">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%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="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER">%d</xliff:g> lần. 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_now_erasing_user" product="default" msgid="7729009752252111673">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER">%d</xliff:g> lần. 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_profile" product="tablet" msgid="4621778507387853694">"Bạn đã mở khóa máy tính bảng sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, 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_erase_profile" product="default" msgid="6853071165802933545">"Bạn đã mở khóa điện thoại sai <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần mở khóa không thành công nữa, 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_erase_profile" product="tablet" msgid="4621778507387853694">"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, 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_erase_profile" product="default" msgid="6853071165802933545">"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, 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="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%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 Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%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 Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. 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 Vui lòng 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="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. 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 Vui lòng 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="30531039455764924">"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 bạn."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<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/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index c7b217c..dc017fb 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"请重新输入正确的PUK码。如果尝试错误次数过多,SIM卡将永久停用。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN码不匹配"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"图案尝试次数过多"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经<xliff:g id="NUMBER_0">%d</xliff:g>次输错了PIN码。\n\n请在<xliff:g id="NUMBER_1">%d</xliff:g>秒后重试。"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次输错密码。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。\n\n请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,平板电脑将会被重置,这会删除其中的所有数据。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,手机将会被重置,这会删除其中的所有数据。"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已经<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="7813713389422226531">"您已连续 <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="74089475965050805">"您已连续 <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="8774056606869646621">"您已经 <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="1843331751334128428">"您已经 <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="258925501999698032">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。平板电脑将会被重置,这会删除其中的所有数据。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。手机将会被重置,这会删除其中的所有数据。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此用户,这会删除所有的用户数据。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此用户,这会删除所有的用户数据。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您已经 <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="6945823186629369880">"您已经 <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_erasing_user" product="tablet" msgid="3963486905355778734">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。系统将移除此用户,这会删除所有的用户数据。"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。系统将移除此用户,这会删除所有的用户数据。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁平板电脑。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地尝试解锁手机。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您已经 <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_profile" product="default" msgid="6853071165802933545">"您已经 <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_erasing_profile" product="tablet" msgid="4686386497449912146">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁平板电脑。系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已经 <xliff:g id="NUMBER">%d</xliff:g> 次错误地尝试解锁手机。系统将移除此工作资料,这会删除所有的工作资料数据。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁平板电脑。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已连续 <xliff:g id="NUMBER_0">%d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已连续 <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="1437638152015574839">"您已连续 <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="30531039455764924">"SIM卡PIN码不正确,您现在必须联系运营商为您解锁设备。"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM 卡 PIN 码不正确,您还可尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 542e1b8..82802d4 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"請重新輸入正確的 PUK 碼。如果嘗試輸入的次數過多,SIM 卡將永久停用。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖案嘗試次數過多"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已輸入錯誤的 PIN 碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您已輸入錯誤的密碼 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,平板電腦將被重設,平板電腦的所有資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,手機將被重設,手機的所有資料將因此被刪除。"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您已輸入錯誤的 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="7813713389422226531">"您已輸入錯誤的密碼 <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="74089475965050805">"您已畫錯解鎖圖案 <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="8774056606869646621">"您已 <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="1843331751334128428">"您已 <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="258925501999698032">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。平板電腦將被重設,平板電腦的所有資料將因此被刪除。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。手機將被重設,手機的所有資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該使用者將被移除,所有使用者資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該使用者將被移除,所有使用者資料將因此被刪除。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您已 <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="6945823186629369880">"您已 <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_erasing_user" product="tablet" msgid="3963486905355778734">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖平板電腦。該使用者將被移除,所有使用者資料將因此被刪除。"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。該使用者將被移除,所有使用者資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖平板電腦。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次錯誤解鎖手機。如再解鎖失敗 <xliff:g id="NUMBER_1">%d</xliff:g> 次,該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您已 <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_profile" product="default" msgid="6853071165802933545">"您已 <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_erasing_profile" product="tablet" msgid="4686386497449912146">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖平板電腦。該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您已 <xliff:g id="NUMBER">%d</xliff:g> 次錯誤解鎖手機。該工作設定檔將被移除,所有設定檔資料將因此被刪除。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的平板電腦。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已畫錯解鎖圖案 <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="1437638152015574839">"您已畫錯解鎖圖案 <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="30531039455764924">"SIM PIN 碼不正確,您現在必須聯絡流動網絡供應商為您的裝置解鎖。"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM PIN 碼不正確,您還有 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會輸入。</item>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 56d0573..800d0a0 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"重新輸入正確的 PUK 碼。如果錯誤次數過多,SIM 卡將會永久停用。"</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN 碼不符"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"圖形嘗試次數過多"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 PIN 已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"您的密碼已輸錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次。\n\n請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這台平板電腦將會重設,其中的所有資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,系統會重設您的手機,其中的所有資料也會一併遭到刪除。"</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"您的 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="7813713389422226531">"您的密碼已輸錯 <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="74089475965050805">"您的解鎖圖形已畫錯 <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="8774056606869646621">"您嘗試解鎖平板電腦已失敗 <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="1843331751334128428">"您嘗試解鎖手機已失敗 <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="258925501999698032">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。這台平板電腦將會重設,其中的所有資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。系統會重設您的手機,其中的所有資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"您嘗試解鎖平板電腦已失敗 <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="6945823186629369880">"您嘗試解鎖手機已失敗 <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_erasing_user" product="tablet" msgid="3963486905355778734">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。這位使用者將遭到移除,對方的所有使用者資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,目前還剩 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次機會。如果失敗次數超過限制,您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"您嘗試解鎖平板電腦已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"您嘗試解鎖手機已失敗 <xliff:g id="NUMBER">%d</xliff:g> 次。您的 Work 設定檔將遭到移除,所有設定檔資料也會一併遭到刪除。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <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="1437638152015574839">"您的解鎖圖形已畫錯 <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="30531039455764924">"SIM 卡的 PIN 碼輸入錯誤,您現在必須請行動通訊業者為裝置解鎖。"</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="other">SIM 卡的 PIN 碼輸入錯誤,您還可以再試 <xliff:g id="NUMBER_1">%d</xliff:g> 次。</item>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index c29619c..e1a54d1 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -77,23 +77,23 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Faka kabusha ikhodi ye-PUK elungile. Imizamo ephindiwe izokhubaza unaphakade i-SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Iphinikhodi ayifani"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Kunemizamo eminingi kakhulu yephathini"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Ubhale iphinikhodi ykho ngendlela engafanele izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Ubhale iphasiwedi yakho ngendlela engafanele <xliff:g id="NUMBER_0">%d</xliff:g> izikhathi. \n\nZama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Udwebe iphathini yakho yokuvula ngendlela engafanele-<xliff:g id="NUMBER_0">%d</xliff:g>. \n\n Zama futhi emasekhondini angu-<xliff:g id="NUMBER_1">%d</xliff:g>"</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, le thebulethi izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, le foni izosethwa kabusha, okuzosusa yonke idatha yayo."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"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="7813713389422226531">"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="74089475965050805">"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="8774056606869646621">"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="1843331751334128428">"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="258925501999698032">"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="7154028908459817066">"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="6159955099372112688">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
- <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
+ <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"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="6945823186629369880">"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>
<string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
<string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER">%d</xliff:g>. Lo msebenzisi uzosuswa, okuzosusa yonke idatha yomsebenzisi."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"Uzame ngokungalungile ukuvula ithebulethi izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
- <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Uzame ngokungalungile ukuvula ifoni izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Ngemuva kwemizamo engaphezulu kwengu-<xliff:g id="NUMBER_1">%d</xliff:g> engaphumelelanga, iphrofayela yomsebenzi, izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"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, iphrofayela yomsebenzi izosuswa, okuzosusa yonke idatha yephrofayela."</string>
+ <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"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, iphrofayela yomsebenzi, izosuswa, okuzosusa yonke idatha yephrofayela."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"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="4951507352869831265">"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="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%d</xliff:g>. Emva <xliff:g id="NUMBER_1">%d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%d</xliff:g>"</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%d</xliff:g> amasekhondi."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Udwebe ngokungalungile iphathini yakho yokuvula izikhathi ezingu-<xliff:g id="NUMBER_0">%1$d</xliff:g>. Emva <xliff:g id="NUMBER_1">%2$d</xliff:g> kweminye imizamo engaphumelelanga, uzocelwa ukuvula ithebhulethi yakho usebenzisa ukungena ngemvume kwi-Google.\n\n Sicela uzame futhi emuva kwamasekhondi angu-<xliff:g id="NUMBER_2">%3$d</xliff:g>"</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"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> amasekhondi."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"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="6721575017538162249">
<item quantity="one">Ikhodi engalungile yephinikhodi ye-SIM, unemizamo engu-<xliff:g id="NUMBER_1">%d</xliff:g> esele.</item>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index d1e84f5..dea5fa0 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -170,29 +170,29 @@
<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 -->
<string name="kg_too_many_failed_pin_attempts_dialog_message">
- You have incorrectly typed your PIN <xliff:g id="number">%d</xliff:g> times.
- \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+ You have incorrectly typed your PIN <xliff:g id="number">%1$d</xliff:g> times.
+ \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
</string>
<!-- Message shown in dialog when max number of attempts are reached for password screen of keyguard -->
<string name="kg_too_many_failed_password_attempts_dialog_message">
- You have incorrectly typed your password <xliff:g id="number">%d</xliff:g> times.
- \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+ You have incorrectly typed your password <xliff:g id="number">%1$d</xliff:g> times.
+ \n\nTry again in <xliff:g id="number">%2$d</xliff:g> seconds.
</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message">
- You have incorrectly drawn your unlock pattern <xliff:g id="number">%d</xliff:g> times.
- \n\nTry again in <xliff:g id="number">%d</xliff:g> seconds.
+ You have incorrectly drawn your unlock pattern <xliff:g id="number">%1$d</xliff:g> times.
+ \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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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] -->
@@ -208,14 +208,14 @@
<!-- 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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] -->
@@ -231,14 +231,14 @@
<!-- 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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] -->
@@ -255,18 +255,18 @@
<!-- 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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">%d</xliff:g> seconds.
+ 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">%d</xliff:g> times.
- After <xliff:g id="number">%d</xliff:g> more unsuccessful attempts,
+ 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">%d</xliff:g> seconds.
+ 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.
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index 3c2fa36..67bbf78 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -6,6 +6,7 @@
LOCAL_PACKAGE_NAME := MtpDocumentsProvider
LOCAL_CERTIFICATE := media
LOCAL_PRIVILEGED_MODULE := true
+LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
include $(BUILD_PACKAGE)
-include $(LOCAL_PATH)/tests/Android.mk
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/MtpDocumentsProvider/jni/Android.mk b/packages/MtpDocumentsProvider/jni/Android.mk
new file mode 100644
index 0000000..d545b14
--- /dev/null
+++ b/packages/MtpDocumentsProvider/jni/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ com_android_mtp_AppFuse.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ libnativehelper \
+ liblog
+
+LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
+LOCAL_MODULE := libappfuse_jni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
new file mode 100644
index 0000000..f9fb85c4
--- /dev/null
+++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specic language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AppFuseJNI"
+#include "utils/Log.h"
+
+#include <assert.h>
+#include <dirent.h>
+#include <inttypes.h>
+
+#include <linux/fuse.h>
+#include <sys/stat.h>
+
+#include <map>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "nativehelper/ScopedPrimitiveArray.h"
+
+namespace {
+
+// Maximum number of bytes to write in one request.
+constexpr size_t MAX_WRITE = 256 * 1024;
+constexpr size_t NUM_MAX_HANDLES = 1024;
+
+// Largest possible request.
+// The request size is bounded by the maximum size of a FUSE_WRITE request
+// because it has the largest possible data payload.
+constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
+ sizeof(struct fuse_write_in) + MAX_WRITE;
+
+static jclass app_fuse_class;
+static jmethodID app_fuse_get_file_size;
+static jmethodID app_fuse_get_object_bytes;
+
+struct FuseRequest {
+ char buffer[MAX_REQUEST_SIZE];
+ FuseRequest() {}
+ const struct fuse_in_header& header() const {
+ return *(const struct fuse_in_header*) buffer;
+ }
+ const void* data() const {
+ return (buffer + sizeof(struct fuse_in_header));
+ }
+ size_t data_length() const {
+ return header().len - sizeof(struct fuse_in_header);
+ }
+};
+
+class ScopedFd {
+ int mFd;
+
+public:
+ explicit ScopedFd(int fd) : mFd(fd) {}
+ ~ScopedFd() {
+ close(mFd);
+ }
+ operator int() {
+ return mFd;
+ }
+};
+
+/**
+ * The class is used to access AppFuse class in Java from fuse handlers.
+ */
+class AppFuse {
+ JNIEnv* env_;
+ jobject self_;
+
+ // Map between file handle and inode.
+ std::map<uint32_t, uint64_t> handles_;
+ uint32_t handle_counter_;
+
+public:
+ AppFuse(JNIEnv* env, jobject self) :
+ env_(env), self_(self), handle_counter_(0) {}
+
+ bool handle_fuse_request(int fd, const FuseRequest& req) {
+ ALOGV("Request op=%d", req.header().opcode);
+ switch (req.header().opcode) {
+ // TODO: Handle more operations that are enough to provide seekable
+ // FD.
+ case FUSE_LOOKUP:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
+ return true;
+ case FUSE_INIT:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_init);
+ return true;
+ case FUSE_GETATTR:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
+ return true;
+ case FUSE_FORGET:
+ return false;
+ case FUSE_OPEN:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_open);
+ return true;
+ case FUSE_READ:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_read, 8192);
+ return true;
+ case FUSE_RELEASE:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_release, 0);
+ return true;
+ case FUSE_FLUSH:
+ invoke_handler(fd, req, &AppFuse::handle_fuse_flush, 0);
+ return true;
+ default: {
+ ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
+ req.header().opcode,
+ req.header().unique,
+ req.header().nodeid);
+ fuse_reply(fd, req.header().unique, -ENOSYS, NULL, 0);
+ return true;
+ }
+ }
+ }
+
+private:
+ int handle_fuse_lookup(const fuse_in_header& header,
+ const char* name,
+ fuse_entry_out* out,
+ uint32_t* /*unused*/) {
+ if (header.nodeid != 1) {
+ return -ENOENT;
+ }
+
+ const int n = atoi(name);
+ if (n == 0) {
+ return -ENOENT;
+ }
+
+ int64_t size = get_file_size(n);
+ if (size < 0) {
+ return -ENOENT;
+ }
+
+ out->nodeid = n;
+ out->attr_valid = 10;
+ out->entry_valid = 10;
+ out->attr.ino = n;
+ out->attr.mode = S_IFREG | 0777;
+ out->attr.size = size;
+ return 0;
+ }
+
+ int handle_fuse_init(const fuse_in_header&,
+ const fuse_init_in* in,
+ fuse_init_out* out,
+ uint32_t* reply_size) {
+ // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+ // defined (fuse version 7.6). The structure is the same from 7.6 through
+ // 7.22. Beginning with 7.23, the structure increased in size and added
+ // new parameters.
+ if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
+ ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
+ "Expected at least %d.6",
+ in->major, in->minor, FUSE_KERNEL_VERSION);
+ return -1;
+ }
+
+ // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
+ out->minor = std::min(in->minor, 15u);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+ // FUSE_KERNEL_VERSION >= 23.
+
+ // If the kernel only works on minor revs older than or equal to 22,
+ // then use the older structure size since this code only uses the 7.22
+ // version of the structure.
+ if (in->minor <= 22) {
+ *reply_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
+#else
+ // Don't drop this line to prevent an 'unused' compile error.
+ *reply_size = sizeof(fuse_init_out);
+#endif
+
+ out->major = FUSE_KERNEL_VERSION;
+ out->max_readahead = in->max_readahead;
+ out->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+ out->max_background = 32;
+ out->congestion_threshold = 32;
+ out->max_write = MAX_WRITE;
+
+ return 0;
+ }
+
+ int handle_fuse_getattr(const fuse_in_header& header,
+ const fuse_getattr_in* /* in */,
+ fuse_attr_out* out,
+ uint32_t* /*unused*/) {
+ if (header.nodeid != 1) {
+ return -ENOENT;
+ }
+ out->attr_valid = 1000 * 60 * 10;
+ out->attr.ino = header.nodeid;
+ out->attr.mode = S_IFDIR | 0777;
+ out->attr.size = 0;
+ return 0;
+ }
+
+ int handle_fuse_open(const fuse_in_header& header,
+ const fuse_open_in* /* in */,
+ fuse_open_out* out,
+ uint32_t* /*unused*/) {
+ if (handles_.size() >= NUM_MAX_HANDLES) {
+ // Too many open files.
+ return -EMFILE;
+ }
+ uint32_t handle;
+ do {
+ handle = handle_counter_++;
+ } while (handles_.count(handle) != 0);
+
+ handles_.insert(std::make_pair(handle, header.nodeid));
+ out->fh = handle;
+ return 0;
+ }
+
+ int handle_fuse_read(const fuse_in_header& /* header */,
+ const fuse_read_in* in,
+ void* out,
+ uint32_t* reply_size) {
+ const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
+ if (it == handles_.end()) {
+ return -EBADF;
+ }
+ const int64_t result = get_object_bytes(
+ it->second,
+ in->offset,
+ in->size,
+ out);
+ if (result < 0) {
+ return -EIO;
+ }
+ *reply_size = static_cast<size_t>(result);
+ return 0;
+ }
+
+ int handle_fuse_release(const fuse_in_header& /* header */,
+ const fuse_release_in* in,
+ void* /* out */,
+ uint32_t* /* reply_size */) {
+ handles_.erase(in->fh);
+ return 0;
+ }
+
+ int handle_fuse_flush(const fuse_in_header& /* header */,
+ const void* /* in */,
+ void* /* out */,
+ uint32_t* /* reply_size */) {
+ return 0;
+ }
+
+ template <typename T, typename S>
+ void invoke_handler(int fd,
+ const FuseRequest& request,
+ int (AppFuse::*handler)(const fuse_in_header&,
+ const T*,
+ S*,
+ uint32_t*),
+ uint32_t reply_size = sizeof(S)) {
+ char reply_data[reply_size];
+ memset(reply_data, 0, reply_size);
+ const int reply_code = (this->*handler)(
+ request.header(),
+ static_cast<const T*>(request.data()),
+ reinterpret_cast<S*>(reply_data),
+ &reply_size);
+ fuse_reply(
+ fd,
+ request.header().unique,
+ reply_code,
+ reply_data,
+ reply_size);
+ }
+
+ int64_t get_file_size(int inode) {
+ return static_cast<int64_t>(env_->CallLongMethod(
+ self_,
+ app_fuse_get_file_size,
+ static_cast<int>(inode)));
+ }
+
+ int64_t get_object_bytes(
+ int inode,
+ uint64_t offset,
+ uint32_t size,
+ void* buf) {
+ const uint32_t read_size = static_cast<uint32_t>(std::min(
+ static_cast<uint64_t>(size),
+ get_file_size(inode) - offset));
+ const jbyteArray array = (jbyteArray) env_->CallObjectMethod(
+ self_,
+ app_fuse_get_object_bytes,
+ inode,
+ offset,
+ read_size);
+ if (array == nullptr) {
+ return -1;
+ }
+ ScopedByteArrayRO bytes(env_, array);
+ if (bytes.size() != read_size || bytes.get() == nullptr) {
+ return -1;
+ }
+
+ memcpy(buf, bytes.get(), read_size);
+ return read_size;
+ }
+
+ static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
+ size_t reply_size) {
+ // Don't send any data for error case.
+ if (reply_code != 0) {
+ reply_size = 0;
+ }
+
+ struct fuse_out_header hdr;
+ hdr.len = reply_size + sizeof(hdr);
+ hdr.error = reply_code;
+ hdr.unique = unique;
+
+ struct iovec vec[2];
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = reply_data;
+ vec[1].iov_len = reply_size;
+
+ const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
+ if (res < 0) {
+ ALOGE("*** REPLY FAILED *** %d\n", errno);
+ }
+ }
+};
+
+jboolean com_android_mtp_AppFuse_start_app_fuse_loop(
+ JNIEnv* env, jobject self, jint jfd) {
+ ScopedFd fd(dup(static_cast<int>(jfd)));
+ AppFuse appfuse(env, self);
+
+ ALOGD("Start fuse loop.");
+ while (true) {
+ FuseRequest request;
+
+ const ssize_t result = TEMP_FAILURE_RETRY(
+ read(fd, request.buffer, sizeof(request.buffer)));
+ if (result < 0) {
+ if (errno == ENODEV) {
+ ALOGE("Someone stole our marbles!\n");
+ return JNI_FALSE;
+ }
+ ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
+ continue;
+ }
+
+ const size_t length = static_cast<size_t>(result);
+ if (length < sizeof(struct fuse_in_header)) {
+ ALOGE("request too short: len=%zu\n", length);
+ continue;
+ }
+
+ if (request.header().len != length) {
+ ALOGE("malformed header: len=%zu, hdr->len=%u\n",
+ length, request.header().len);
+ continue;
+ }
+
+ if (!appfuse.handle_fuse_request(fd, request)) {
+ return JNI_TRUE;
+ }
+ }
+}
+
+static const JNINativeMethod gMethods[] = {
+ {
+ "native_start_app_fuse_loop",
+ "(I)Z",
+ (void *) com_android_mtp_AppFuse_start_app_fuse_loop
+ }
+};
+
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
+ JNIEnv* env = nullptr;
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGE("ERROR: GetEnv failed\n");
+ return -1;
+
+ }
+ assert(env != nullptr);
+
+ jclass clazz = env->FindClass("com/android/mtp/AppFuse");
+ if (clazz == nullptr) {
+ ALOGE("Can't find com/android/mtp/AppFuse");
+ return -1;
+ }
+
+ app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (app_fuse_class == nullptr) {
+ ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
+ return -1;
+ }
+
+ app_fuse_get_file_size = env->GetMethodID(
+ app_fuse_class, "getFileSize", "(I)J");
+ if (app_fuse_get_file_size == nullptr) {
+ ALOGE("Can't find getFileSize");
+ return -1;
+ }
+
+ app_fuse_get_object_bytes = env->GetMethodID(
+ app_fuse_class, "getObjectBytes", "(IJI)[B");
+ if (app_fuse_get_object_bytes == nullptr) {
+ ALOGE("Can't find getObjectBytes");
+ return -1;
+ }
+
+ const int result = android::AndroidRuntime::registerNativeMethods(
+ env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
+ if (result < 0) {
+ return -1;
+ }
+
+ return JNI_VERSION_1_4;
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
new file mode 100644
index 0000000..5ffd7cf
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mtp;
+
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.storage.StorageManager;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+/**
+ * TODO: Remove VisibleForTesting class.
+ */
+@VisibleForTesting
+public class AppFuse {
+ static {
+ System.loadLibrary("appfuse_jni");
+ }
+
+ private final String mName;
+ private final Callback mCallback;
+ private final Thread mMessageThread;
+ private ParcelFileDescriptor mDeviceFd;
+
+ @VisibleForTesting
+ AppFuse(String name, Callback callback) {
+ mName = name;
+ mCallback = callback;
+ mMessageThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ native_start_app_fuse_loop(mDeviceFd.getFd());
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void mount(StorageManager storageManager) {
+ mDeviceFd = storageManager.mountAppFuse(mName);
+ mMessageThread.start();
+ }
+
+ @VisibleForTesting
+ void close() {
+ try {
+ // Remote side of ParcelFileDescriptor is tracking the close of mDeviceFd, and unmount
+ // the corresponding fuse file system. The mMessageThread will receive FUSE_FORGET, and
+ // then terminate itself.
+ mDeviceFd.close();
+ mMessageThread.join();
+ } catch (IOException exp) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to close device FD.", exp);
+ } catch (InterruptedException exp) {
+ Log.e(MtpDocumentsProvider.TAG, "Failed to terminate message thread.", exp);
+ }
+ }
+
+ /**
+ * @param i
+ * @throws FileNotFoundException
+ */
+ @VisibleForTesting
+ public ParcelFileDescriptor openFile(int i) throws FileNotFoundException {
+ return ParcelFileDescriptor.open(new File(
+ getMountPoint(),
+ Integer.toString(i)),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+
+ @VisibleForTesting
+ File getMountPoint() {
+ return new File("/mnt/appfuse/" + Process.myUid() + "_" + mName);
+ }
+
+ static interface Callback {
+ long getFileSize(int inode) throws FileNotFoundException;
+ byte[] getObjectBytes(int inode, long offset, int size) throws IOException;
+ }
+
+ @VisibleForTesting
+ private long getFileSize(int inode) {
+ try {
+ return mCallback.getFileSize(inode);
+ } catch (IOException e) {
+ return -1;
+ }
+ }
+
+ @VisibleForTesting
+ private byte[] getObjectBytes(int inode, long offset, int size) {
+ try {
+ return mCallback.getObjectBytes(inode, offset, size);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ private native boolean native_start_app_fuse_loop(int fd);
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
index 322246a..ac47067 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Mapper.java
@@ -56,22 +56,29 @@
mDatabase = database;
}
- synchronized String putDeviceDocument(int deviceId, String name, MtpRoot[] roots) {
+ /**
+ * Puts device information to database.
+ * @return If device is added to the database.
+ */
+ synchronized boolean putDeviceDocument(MtpDeviceRecord device) {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
Preconditions.checkState(mMappingMode.containsKey(/* no parent for root */ null));
database.beginTransaction();
try {
final ContentValues[] valuesList = new ContentValues[1];
+ final ContentValues[] extraValuesList = new ContentValues[1];
valuesList[0] = new ContentValues();
- MtpDatabase.getDeviceDocumentValues(valuesList[0], deviceId, name, roots);
- putDocuments(
+ extraValuesList[0] = new ContentValues();
+ MtpDatabase.getDeviceDocumentValues(valuesList[0], extraValuesList[0], device);
+ final boolean changed = putDocuments(
valuesList,
+ extraValuesList,
COLUMN_PARENT_DOCUMENT_ID + " IS NULL",
EMPTY_ARGS,
/* heuristic */ false,
COLUMN_DEVICE_ID);
database.setTransactionSuccessful();
- return valuesList[0].getAsString(Document.COLUMN_DOCUMENT_ID);
+ return changed;
} finally {
database.endTransaction();
}
@@ -84,7 +91,7 @@
* @param roots List of root information.
* @return If roots are added or removed from the database.
*/
- synchronized boolean putRootDocuments(
+ synchronized boolean putStorageDocuments(
String parentDocumentId, Resources resources, MtpRoot[] roots) {
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
database.beginTransaction();
@@ -105,36 +112,21 @@
throw new Error("Unexpected map mode.");
}
final ContentValues[] valuesList = new ContentValues[roots.length];
+ final ContentValues[] extraValuesList = new ContentValues[roots.length];
for (int i = 0; i < roots.length; i++) {
valuesList[i] = new ContentValues();
+ extraValuesList[i] = new ContentValues();
MtpDatabase.getStorageDocumentValues(
- valuesList[i], resources, parentDocumentId, roots[i]);
+ valuesList[i], extraValuesList[i], resources, parentDocumentId, roots[i]);
}
final boolean changed = putDocuments(
valuesList,
+ extraValuesList,
COLUMN_PARENT_DOCUMENT_ID + "=?",
strings(parentDocumentId),
heuristic,
mapColumn);
- final ContentValues values = new ContentValues();
- int i = 0;
- for (final MtpRoot root : roots) {
- // Use the same value for the root ID and the corresponding document ID.
- final String documentId = valuesList[i++].getAsString(Document.COLUMN_DOCUMENT_ID);
- // If it fails to insert/update documents, the document ID will be set with -1.
- // In this case we don't insert/update root extra information neither.
- if (documentId == null) {
- continue;
- }
- values.put(Root.COLUMN_ROOT_ID, documentId);
- values.put(
- Root.COLUMN_FLAGS,
- Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
- values.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
- values.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
- values.put(Root.COLUMN_MIME_TYPES, "");
- database.replace(TABLE_ROOT_EXTRA, null, values);
- }
+
database.setTransactionSuccessful();
return changed;
} finally {
@@ -172,6 +164,7 @@
}
putDocuments(
valuesList,
+ null,
COLUMN_PARENT_DOCUMENT_ID + "=?",
strings(parentId),
heuristic,
@@ -249,10 +242,11 @@
* If the mapping mode is not heuristic, it just adds the rows to the database or updates the
* existing rows with the new values. If the mapping mode is heuristic, it adds some new rows as
* 'pending' state when that rows may be corresponding to existing 'invalidated' rows. Then
- * {@link #stopAddingDocuments(String, String[], String)} turns the pending rows into 'valid'
+ * {@link #stopAddingDocuments(String)} turns the pending rows into 'valid'
* rows. If the methods adds rows to database, it updates valueList with correct document ID.
*
* @param valuesList Values for documents to be stored in the database.
+ * @param rootExtraValuesList Values for root extra to be stored in the database.
* @param selection SQL where closure to select rows that shares the same parent.
* @param args Argument for selection SQL.
* @param heuristic Whether the mapping mode is heuristic.
@@ -260,6 +254,7 @@
*/
private boolean putDocuments(
ContentValues[] valuesList,
+ @Nullable ContentValues[] rootExtraValuesList,
String selection,
String[] args,
boolean heuristic,
@@ -268,7 +263,14 @@
boolean added = false;
database.beginTransaction();
try {
- for (final ContentValues values : valuesList) {
+ for (int i = 0; i < valuesList.length; i++) {
+ final ContentValues values = valuesList[i];
+ final ContentValues rootExtraValues;
+ if (rootExtraValuesList != null) {
+ rootExtraValues = rootExtraValuesList[i];
+ } else {
+ rootExtraValues = null;
+ }
final Cursor candidateCursor = database.query(
TABLE_DOCUMENTS,
strings(Document.COLUMN_DOCUMENT_ID),
@@ -286,25 +288,26 @@
final long rowId;
if (candidateCursor.getCount() == 0) {
rowId = database.insert(TABLE_DOCUMENTS, null, values);
- if (rowId == -1) {
- throw new SQLiteException("Failed to put a document into database.");
- }
added = true;
} else if (!heuristic) {
candidateCursor.moveToNext();
- final String documentId = candidateCursor.getString(0);
- rowId = database.update(
+ rowId = candidateCursor.getLong(0);
+ database.update(
TABLE_DOCUMENTS,
values,
SELECTION_DOCUMENT_ID,
- strings(documentId));
+ strings(rowId));
} else {
values.put(COLUMN_ROW_STATE, ROW_STATE_PENDING);
- rowId = database.insert(TABLE_DOCUMENTS, null, values);
+ rowId = database.insertOrThrow(TABLE_DOCUMENTS, null, values);
}
// Document ID is a primary integer key of the table. So the returned row
// IDs should be same with the document ID.
values.put(Document.COLUMN_DOCUMENT_ID, rowId);
+ if (rootExtraValues != null) {
+ rootExtraValues.put(Root.COLUMN_ROOT_ID, rowId);
+ database.replace(TABLE_ROOT_EXTRA, null, rootExtraValues);
+ }
} finally {
candidateCursor.close();
}
@@ -452,12 +455,15 @@
final SQLiteDatabase database = mDatabase.getSQLiteDatabase();
values.clear();
final Cursor cursor = database.query(table, null, selection, args, null, null, null, "1");
- if (cursor.getCount() == 0) {
- return;
+ try {
+ if (cursor.getCount() == 0) {
+ return;
+ }
+ cursor.moveToNext();
+ DatabaseUtils.cursorRowToContentValues(cursor, values);
+ } finally {
+ cursor.close();
}
- cursor.moveToNext();
- DatabaseUtils.cursorRowToContentValues(cursor, values);
- cursor.close();
}
/**
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 1ba3e31..112914e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -18,11 +18,14 @@
import static com.android.mtp.MtpDatabaseConstants.*;
+import android.annotation.Nullable;
import android.content.ContentValues;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.DatabaseUtils;
import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
@@ -36,8 +39,6 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Objects;
/**
@@ -108,17 +109,93 @@
* @return Database cursor.
*/
Cursor queryRoots(String[] columnNames) {
- final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
- builder.setTables(JOIN_ROOTS);
- builder.setProjectionMap(COLUMN_MAP_ROOTS);
- return builder.query(
- mDatabase,
- columnNames,
- COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?",
- strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_STORAGE),
+ final String selection =
+ COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_DOCUMENT_TYPE + " = ?";
+ final Cursor deviceCursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(COLUMN_DEVICE_ID),
+ selection,
+ strings(ROW_STATE_VALID, ROW_STATE_INVALIDATED, DOCUMENT_TYPE_DEVICE),
+ COLUMN_DEVICE_ID,
null,
null,
null);
+
+ try {
+ final SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
+ builder.setTables(JOIN_ROOTS);
+ builder.setProjectionMap(COLUMN_MAP_ROOTS);
+ final MatrixCursor result = new MatrixCursor(columnNames);
+ final ContentValues values = new ContentValues();
+
+ while (deviceCursor.moveToNext()) {
+ final int deviceId = deviceCursor.getInt(0);
+ final Cursor storageCursor = builder.query(
+ mDatabase,
+ columnNames,
+ selection + " AND " + COLUMN_DEVICE_ID + " = ?",
+ strings(ROW_STATE_VALID,
+ ROW_STATE_INVALIDATED,
+ DOCUMENT_TYPE_STORAGE,
+ deviceId),
+ null,
+ null,
+ null);
+ try {
+ values.clear();
+ if (storageCursor.getCount() == 1) {
+ storageCursor.moveToNext();
+ DatabaseUtils.cursorRowToContentValues(storageCursor, values);
+ } else {
+ final Cursor cursor = builder.query(
+ mDatabase,
+ columnNames,
+ selection + " AND " + COLUMN_DEVICE_ID + " = ?",
+ strings(ROW_STATE_VALID,
+ ROW_STATE_INVALIDATED,
+ DOCUMENT_TYPE_DEVICE,
+ deviceId),
+ null,
+ null,
+ null);
+ try {
+ cursor.moveToNext();
+ DatabaseUtils.cursorRowToContentValues(cursor, values);
+ } finally {
+ cursor.close();
+ }
+
+ long capacityBytes = 0;
+ long availableBytes = 0;
+ int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+ int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+ while (storageCursor.moveToNext()) {
+ // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
+ // calculate corresponding values.
+ if (capacityIndex != -1) {
+ capacityBytes += cursor.getLong(capacityIndex);
+ }
+ if (availableIndex != -1) {
+ availableBytes += cursor.getLong(availableIndex);
+ }
+ }
+ values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+ values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+ }
+ } finally {
+ storageCursor.close();
+ }
+
+ final RowBuilder row = result.newRow();
+ for (final String key : values.keySet()) {
+ row.add(key, values.get(key));
+ }
+ }
+
+ return result;
+ } finally {
+ deviceCursor.close();
+ }
}
/**
@@ -183,6 +260,27 @@
deleteDocumentsAndRoots(COLUMN_DEVICE_ID + "=?", strings(deviceId));
}
+ @Nullable String getDocumentIdForDevice(int deviceId) {
+ final Cursor cursor = mDatabase.query(
+ TABLE_DOCUMENTS,
+ strings(Document.COLUMN_DOCUMENT_ID),
+ COLUMN_DOCUMENT_TYPE + " = ? AND " + COLUMN_DEVICE_ID + " = ?",
+ strings(DOCUMENT_TYPE_DEVICE, deviceId),
+ null,
+ null,
+ null,
+ "1");
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ } else {
+ return null;
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
/**
* Obtains parent document ID.
* @param documentId
@@ -362,25 +460,31 @@
}
static void getDeviceDocumentValues(
- ContentValues values, int deviceId, String name, MtpRoot[] roots) {
+ ContentValues values,
+ ContentValues extraValues,
+ MtpDeviceRecord device) {
values.clear();
- values.put(COLUMN_DEVICE_ID, deviceId);
+ values.put(COLUMN_DEVICE_ID, device.deviceId);
values.putNull(COLUMN_STORAGE_ID);
values.putNull(COLUMN_OBJECT_HANDLE);
values.putNull(COLUMN_PARENT_DOCUMENT_ID);
values.put(COLUMN_ROW_STATE, ROW_STATE_VALID);
values.put(COLUMN_DOCUMENT_TYPE, DOCUMENT_TYPE_DEVICE);
values.put(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
- values.put(Document.COLUMN_DISPLAY_NAME, name);
+ values.put(Document.COLUMN_DISPLAY_NAME, device.name);
values.putNull(Document.COLUMN_SUMMARY);
values.putNull(Document.COLUMN_LAST_MODIFIED);
values.put(Document.COLUMN_ICON, R.drawable.ic_root_mtp);
values.put(Document.COLUMN_FLAGS, 0);
- long size = 0;
- for (final MtpRoot root : roots) {
- size += root.mMaxCapacity - root.mFreeSpace;
- }
- values.put(Document.COLUMN_SIZE, size);
+ values.putNull(Document.COLUMN_SIZE);
+
+ extraValues.clear();
+ extraValues.put(
+ Root.COLUMN_FLAGS,
+ Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+ extraValues.putNull(Root.COLUMN_AVAILABLE_BYTES);
+ extraValues.putNull(Root.COLUMN_CAPACITY_BYTES);
+ extraValues.put(Root.COLUMN_MIME_TYPES, "");
}
/**
@@ -390,7 +494,11 @@
* @param root Root to be converted {@link ContentValues}.
*/
static void getStorageDocumentValues(
- ContentValues values, Resources resources, String parentDocumentId, MtpRoot root) {
+ ContentValues values,
+ ContentValues extraValues,
+ Resources resources,
+ String parentDocumentId,
+ MtpRoot root) {
values.clear();
values.put(COLUMN_DEVICE_ID, root.mDeviceId);
values.put(COLUMN_STORAGE_ID, root.mStorageId);
@@ -406,6 +514,13 @@
values.put(Document.COLUMN_FLAGS, 0);
values.put(Document.COLUMN_SIZE,
(int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+
+ extraValues.put(
+ Root.COLUMN_FLAGS,
+ Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
+ extraValues.put(Root.COLUMN_AVAILABLE_BYTES, root.mFreeSpace);
+ extraValues.put(Root.COLUMN_CAPACITY_BYTES, root.mMaxCapacity);
+ extraValues.put(Root.COLUMN_MIME_TYPES, "");
}
/**
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
index a233589..f252e0f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabaseConstants.java
@@ -126,14 +126,14 @@
Document.COLUMN_LAST_MODIFIED + " INTEGER," +
Document.COLUMN_ICON + " INTEGER," +
Document.COLUMN_FLAGS + " INTEGER NOT NULL," +
- Document.COLUMN_SIZE + " INTEGER NOT NULL);";
+ Document.COLUMN_SIZE + " INTEGER);";
static final String QUERY_CREATE_ROOT_EXTRA =
"CREATE TABLE " + TABLE_ROOT_EXTRA + " (" +
Root.COLUMN_ROOT_ID + " INTEGER PRIMARY KEY," +
Root.COLUMN_FLAGS + " INTEGER NOT NULL," +
- Root.COLUMN_AVAILABLE_BYTES + " INTEGER NOT NULL," +
- Root.COLUMN_CAPACITY_BYTES + " INTEGER NOT NULL," +
+ Root.COLUMN_AVAILABLE_BYTES + " INTEGER," +
+ Root.COLUMN_CAPACITY_BYTES + " INTEGER," +
Root.COLUMN_MIME_TYPES + " TEXT NOT NULL);";
/**
@@ -145,18 +145,26 @@
COLUMN_MAP_ROOTS = new HashMap<>();
COLUMN_MAP_ROOTS.put(Root.COLUMN_ROOT_ID, TABLE_ROOT_EXTRA + "." + Root.COLUMN_ROOT_ID);
COLUMN_MAP_ROOTS.put(Root.COLUMN_FLAGS, TABLE_ROOT_EXTRA + "." + Root.COLUMN_FLAGS);
- COLUMN_MAP_ROOTS.put(Root.COLUMN_ICON, TABLE_DOCUMENTS + "." + Document.COLUMN_ICON);
COLUMN_MAP_ROOTS.put(
- Root.COLUMN_TITLE, TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME);
- COLUMN_MAP_ROOTS.put(Root.COLUMN_SUMMARY, TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY);
+ Root.COLUMN_ICON,
+ TABLE_DOCUMENTS + "." + Document.COLUMN_ICON + " AS " + Root.COLUMN_ICON);
COLUMN_MAP_ROOTS.put(
- Root.COLUMN_DOCUMENT_ID, TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID);
+ Root.COLUMN_TITLE,
+ TABLE_DOCUMENTS + "." + Document.COLUMN_DISPLAY_NAME + " AS " + Root.COLUMN_TITLE);
+ COLUMN_MAP_ROOTS.put(
+ Root.COLUMN_SUMMARY,
+ TABLE_DOCUMENTS + "." + Document.COLUMN_SUMMARY + " AS " + Root.COLUMN_SUMMARY);
+ COLUMN_MAP_ROOTS.put(
+ Root.COLUMN_DOCUMENT_ID,
+ TABLE_DOCUMENTS + "." + Document.COLUMN_DOCUMENT_ID +
+ " AS " + Root.COLUMN_DOCUMENT_ID);
COLUMN_MAP_ROOTS.put(
Root.COLUMN_AVAILABLE_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_AVAILABLE_BYTES);
COLUMN_MAP_ROOTS.put(
Root.COLUMN_CAPACITY_BYTES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_CAPACITY_BYTES);
COLUMN_MAP_ROOTS.put(
Root.COLUMN_MIME_TYPES, TABLE_ROOT_EXTRA + "." + Root.COLUMN_MIME_TYPES);
+ COLUMN_MAP_ROOTS.put(COLUMN_DEVICE_ID, COLUMN_DEVICE_ID);
}
private static String createJoinFromClosure(
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
copy to packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
index e0d83fd..71df5c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-package com.android.systemui.recents.events.ui;
+package com.android.mtp;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+class MtpDeviceRecord {
+ public final int deviceId;
+ public final String name;
+ public final boolean opened;
+ public final MtpRoot[] roots;
-/**
- * This is sent when a {@link Task} is resized.
- */
-public class ResizeTaskEvent extends EventBus.Event {
-
- public final Task task;
-
- public ResizeTaskEvent(Task task) {
- this.task = task;
+ MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots) {
+ this.deviceId = deviceId;
+ this.name = name;
+ this.opened = opened;
+ this.roots = roots;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index caa2024..3573536 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -245,9 +245,8 @@
void closeDevice(int deviceId) throws IOException, InterruptedException {
synchronized (mDeviceListLock) {
closeDeviceInternal(deviceId);
- mDatabase.removeDeviceRows(deviceId);
}
- mRootScanner.notifyChange();
+ mRootScanner.resume();
}
int[] getOpenedDeviceIds() {
@@ -258,7 +257,12 @@
String getDeviceName(int deviceId) throws IOException {
synchronized (mDeviceListLock) {
- return mMtpManager.getDeviceName(deviceId);
+ for (final MtpDeviceRecord device : mMtpManager.getDevices()) {
+ if (device.deviceId == deviceId) {
+ return device.name;
+ }
+ }
+ throw new IOException("Not found the device: " + Integer.toString(deviceId));
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index e7f94b7..88cab8b 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -17,8 +17,10 @@
package com.android.mtp;
import android.content.Context;
+import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.mtp.MtpConstants;
import android.mtp.MtpDevice;
@@ -26,12 +28,14 @@
import android.mtp.MtpObjectInfo;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.ArrayList;
/**
* The model wrapping android.mtp API.
@@ -39,6 +43,27 @@
class MtpManager {
final static int OBJECT_HANDLE_ROOT_CHILDREN = -1;
+ /**
+ * Subclass for PTP.
+ */
+ private static final int SUBCLASS_STILL_IMAGE_CAPTURE = 1;
+
+ /**
+ * Subclass for Android style MTP.
+ */
+ private static final int SUBCLASS_MTP = 0xff;
+
+ /**
+ * Protocol for Picture Transfer Protocol (PIMA 15470).
+ */
+ private static final int PROTOCOL_PICTURE_TRANSFER = 1;
+
+ /**
+ * Protocol for Android style MTP.
+ */
+ private static final int PROTOCOL_MTP = 0;
+
+
private final UsbManager mManager;
// TODO: Save and restore the set of opened device.
private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
@@ -92,6 +117,33 @@
mDevices.remove(deviceId);
}
+ synchronized MtpDeviceRecord[] getDevices() {
+ final ArrayList<MtpDeviceRecord> devices = new ArrayList<>();
+ for (UsbDevice device : mManager.getDeviceList().values()) {
+ if (!isMtpDevice(device)) {
+ continue;
+ }
+ final boolean opened = mDevices.get(device.getDeviceId()) != null;
+ final String name = device.getProductName();
+ MtpRoot[] roots;
+ if (opened) {
+ try {
+ roots = getRoots(device.getDeviceId());
+ } catch (IOException exp) {
+ Log.e(MtpDocumentsProvider.TAG, exp.getMessage());
+ // If we failed to fetch roots for the device, we still returns device model
+ // with an empty set of roots so that the device is shown DocumentsUI as long as
+ // the device is physically connected.
+ roots = new MtpRoot[0];
+ }
+ } else {
+ roots = new MtpRoot[0];
+ }
+ devices.add(new MtpDeviceRecord(device.getDeviceId(), name, opened, roots));
+ }
+ return devices.toArray(new MtpDeviceRecord[devices.size()]);
+ }
+
synchronized int[] getOpenedDeviceIds() {
final int[] result = new int[mDevices.size()];
for (int i = 0; i < result.length; i++) {
@@ -100,28 +152,6 @@
return result;
}
- String getDeviceName(int deviceId) throws IOException {
- return getDevice(deviceId).getDeviceInfo().getModel();
- }
-
- MtpRoot[] getRoots(int deviceId) throws IOException {
- final MtpDevice device = getDevice(deviceId);
- synchronized (device) {
- final int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- throw new IOException("Failed to obtain storage IDs.");
- }
- final MtpRoot[] results = new MtpRoot[storageIds.length];
- for (int i = 0; i < storageIds.length; i++) {
- results[i] = new MtpRoot(
- device.getDeviceId(),
- device.getDeviceInfo().getModel(),
- device.getStorageInfo(storageIds[i]));
- }
- return results;
- }
- }
-
MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
@@ -212,4 +242,40 @@
}
return device;
}
+
+ private MtpRoot[] getRoots(int deviceId) throws IOException {
+ final MtpDevice device = getDevice(deviceId);
+ synchronized (device) {
+ final int[] storageIds = device.getStorageIds();
+ if (storageIds == null) {
+ throw new IOException("Failed to obtain storage IDs.");
+ }
+ final MtpRoot[] results = new MtpRoot[storageIds.length];
+ for (int i = 0; i < storageIds.length; i++) {
+ results[i] = new MtpRoot(
+ device.getDeviceId(),
+ device.getDeviceInfo().getModel(),
+ device.getStorageInfo(storageIds[i]));
+ }
+ return results;
+ }
+ }
+
+ static boolean isMtpDevice(UsbDevice device) {
+ for (int i = 0; i < device.getInterfaceCount(); i++) {
+ final UsbInterface usbInterface = device.getInterface(i);
+ if ((usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_STILL_IMAGE &&
+ usbInterface.getInterfaceSubclass() == SUBCLASS_STILL_IMAGE_CAPTURE &&
+ usbInterface.getInterfaceProtocol() == PROTOCOL_PICTURE_TRANSFER)) {
+ return true;
+ }
+ if (usbInterface.getInterfaceClass() == UsbConstants.USB_SUBCLASS_VENDOR_SPEC &&
+ usbInterface.getInterfaceSubclass() == SUBCLASS_MTP &&
+ usbInterface.getInterfaceProtocol() == PROTOCOL_MTP &&
+ usbInterface.getName().equals("MTP")) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
index 197dec8..c216c77 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
@@ -2,12 +2,10 @@
import android.content.ContentResolver;
import android.content.res.Resources;
-import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Process;
import android.provider.DocumentsContract;
import android.util.Log;
-import android.util.SparseArray;
import java.io.IOException;
import java.util.HashMap;
@@ -107,37 +105,30 @@
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
int pollingCount = 0;
- while (!Thread.interrupted()) {
- final int[] deviceIds = mManager.getOpenedDeviceIds();
- final Map<String, MtpRoot[]> rootsMap = new HashMap<>();
+ while (true) {
boolean changed = false;
// Update devices.
+ final MtpDeviceRecord[] devices = mManager.getDevices();
mDatabase.getMapper().startAddingDocuments(null /* parentDocumentId */);
- for (final int deviceId : deviceIds) {
- try {
- final MtpRoot[] roots = mManager.getRoots(deviceId);
- final String id = mDatabase.getMapper().putDeviceDocument(
- deviceId,
- mManager.getDeviceName(deviceId),
- roots);
- if (id != null) {
- changed = true;
- rootsMap.put(id, roots);
- }
- } catch (IOException exception) {
- // The error may happen on the device. We would like to continue getting
- // roots for other devices.
- Log.e(MtpDocumentsProvider.TAG, exception.getMessage());
+ for (final MtpDeviceRecord device : devices) {
+ if (mDatabase.getMapper().putDeviceDocument(device)) {
+ changed = true;
}
}
- mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */);
+ if (mDatabase.getMapper().stopAddingDocuments(null /* parentDocumentId */)) {
+ changed = true;
+ }
// Update roots.
- for (final String documentId : rootsMap.keySet()) {
+ for (final MtpDeviceRecord device : devices) {
+ final String documentId = mDatabase.getDocumentIdForDevice(device.deviceId);
+ if (documentId == null) {
+ continue;
+ }
mDatabase.getMapper().startAddingDocuments(documentId);
- if (mDatabase.getMapper().putRootDocuments(
- documentId, mResources, rootsMap.get(documentId))) {
+ if (mDatabase.getMapper().putStorageDocuments(
+ documentId, mResources, device.roots)) {
changed = true;
}
if (mDatabase.getMapper().stopAddingDocuments(documentId)) {
@@ -156,8 +147,7 @@
Thread.sleep(pollingCount > SHORT_POLLING_TIMES ?
LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
} catch (InterruptedException exp) {
- // The while condition handles the interrupted flag.
- continue;
+ break;
}
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
new file mode 100644
index 0000000..76bd2b5
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.mtp;
+
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * TODO: Enable this test after adding SELinux policies for appfuse.
+ */
+@MediumTest
+public class AppFuseTest extends AndroidTestCase {
+
+ public void disabled_testMount() throws ErrnoException, InterruptedException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final AppFuse appFuse = new AppFuse("test", new TestCallback());
+ appFuse.mount(storageManager);
+ final File file = appFuse.getMountPoint();
+ assertTrue(file.isDirectory());
+ assertEquals(1, Os.stat(file.getPath()).st_ino);
+ appFuse.close();
+ assertTrue(1 != Os.stat(file.getPath()).st_ino);
+ }
+
+ public void disabled_testOpenFile() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (INODE == inode) {
+ return 1024;
+ }
+ throw new FileNotFoundException();
+ }
+ });
+ appFuse.mount(storageManager);
+ final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+ fd.close();
+ appFuse.close();
+ }
+
+ public void disabled_testOpenFile_error() {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final AppFuse appFuse = new AppFuse("test", new TestCallback());
+ appFuse.mount(storageManager);
+ try {
+ appFuse.openFile(INODE);
+ fail();
+ } catch (Throwable t) {
+ assertTrue(t instanceof FileNotFoundException);
+ }
+ appFuse.close();
+ }
+
+ public void disabled_testReadFile() throws IOException {
+ final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (inode == INODE) {
+ return BYTES.length;
+ }
+ return super.getFileSize(inode);
+ }
+
+ @Override
+ public byte[] getObjectBytes(int inode, long offset, int size)
+ throws IOException {
+ if (inode == INODE) {
+ return Arrays.copyOfRange(BYTES, (int) offset, (int) offset + size);
+ }
+ return super.getObjectBytes(inode, offset, size);
+ }
+ });
+ appFuse.mount(storageManager);
+ final ParcelFileDescriptor fd = appFuse.openFile(INODE);
+ try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+ final byte[] buffer = new byte[1024];
+ final int size = stream.read(buffer, 0, buffer.length);
+ assertEquals(5, size);
+ }
+ appFuse.close();
+ }
+
+ private static class TestCallback implements AppFuse.Callback {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ throw new FileNotFoundException();
+ }
+
+ @Override
+ public byte[] getObjectBytes(int inode, long offset, int size)
+ throws IOException {
+ throw new IOException();
+ }
+ }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 7bd9a17..f37a55c 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -41,7 +41,7 @@
public void setUp() {
mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", new TestResources(), new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", new TestResources(), new MtpRoot[] {
new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "")
});
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 6d57c5b..1e1ea0a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -74,9 +74,72 @@
return cursor.getString(cursor.getColumnIndex(columnName));
}
- public void testPutRootDocuments() throws Exception {
+ public void testPutSingleStorageDocuments() throws Exception {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+ new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, "")
+ });
+ mDatabase.getMapper().stopAddingDocuments("1");
+
+ {
+ final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES);
+ assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID));
+ assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID));
+ assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE));
+ assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE));
+ assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+ assertTrue(isNull(cursor, COLUMN_SUMMARY));
+ assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED));
+ assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON));
+ assertEquals(0, getInt(cursor, COLUMN_FLAGS));
+ assertEquals(1000, getInt(cursor, COLUMN_SIZE));
+ assertEquals(
+ MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE));
+
+ cursor.close();
+ }
+
+ {
+ final Cursor cursor = mDatabase.queryRoots(new String [] {
+ Root.COLUMN_ROOT_ID,
+ Root.COLUMN_FLAGS,
+ Root.COLUMN_ICON,
+ Root.COLUMN_TITLE,
+ Root.COLUMN_SUMMARY,
+ Root.COLUMN_DOCUMENT_ID,
+ Root.COLUMN_AVAILABLE_BYTES,
+ Root.COLUMN_CAPACITY_BYTES
+ });
+ assertEquals(1, cursor.getCount());
+
+ cursor.moveToNext();
+ assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(
+ Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE,
+ getInt(cursor, Root.COLUMN_FLAGS));
+ assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON));
+ assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE));
+ assertTrue(isNull(cursor, Root.COLUMN_SUMMARY));
+ assertEquals(2, getInt(cursor, Root.COLUMN_DOCUMENT_ID));
+ assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
+ assertEquals(2000, getInt(cursor, Root.COLUMN_CAPACITY_BYTES));
+
+ cursor.close();
+ }
+ }
+
+ public void testPutStorageDocuments() throws Exception {
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""),
new MtpRoot(0, 2, "Device", "Storage", 2000, 4000, ""),
new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 3000, 6000,"")
@@ -111,52 +174,6 @@
cursor.close();
}
-
- {
- final Cursor cursor = mDatabase.queryRoots(new String [] {
- Root.COLUMN_ROOT_ID,
- Root.COLUMN_FLAGS,
- Root.COLUMN_ICON,
- Root.COLUMN_TITLE,
- Root.COLUMN_SUMMARY,
- Root.COLUMN_DOCUMENT_ID,
- Root.COLUMN_AVAILABLE_BYTES,
- Root.COLUMN_CAPACITY_BYTES
- });
- assertEquals(3, cursor.getCount());
-
- cursor.moveToNext();
- assertEquals(1, cursor.getInt(0));
- assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
- assertEquals("Device Storage", cursor.getString(3));
- assertTrue(cursor.isNull(4));
- assertEquals(1, cursor.getInt(5));
- assertEquals(1000, cursor.getInt(6));
- assertEquals(2000, cursor.getInt(7));
-
- cursor.moveToNext();
- assertEquals(2, cursor.getInt(0));
- assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
- assertEquals("Device Storage", cursor.getString(3));
- assertTrue(cursor.isNull(4));
- assertEquals(2, cursor.getInt(5));
- assertEquals(2000, cursor.getInt(6));
- assertEquals(4000, cursor.getInt(7));
-
- cursor.moveToNext();
- assertEquals(3, cursor.getInt(0));
- assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
- assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
- assertEquals("Device /@#%&<>Storage", cursor.getString(3));
- assertTrue(cursor.isNull(4));
- assertEquals(3, cursor.getInt(5));
- assertEquals(3000, cursor.getInt(6));
- assertEquals(6000, cursor.getInt(7));
-
- cursor.close();
- }
}
private MtpObjectInfo createDocument(int objectHandle, String name, int format, int size) {
@@ -245,13 +262,9 @@
MtpDatabaseConstants.COLUMN_STORAGE_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- final String[] rootColumns = new String[] {
- Root.COLUMN_ROOT_ID,
- Root.COLUMN_AVAILABLE_BYTES
- };
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 1000, 0, ""),
new MtpRoot(0, 101, "Device", "Storage B", 1001, 0, "")
});
@@ -270,18 +283,6 @@
cursor.close();
}
- {
- final Cursor cursor = mDatabase.queryRoots(rootColumns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.close();
- }
-
mDatabase.getMapper().clearMapping();
{
@@ -298,20 +299,8 @@
cursor.close();
}
- {
- final Cursor cursor = mDatabase.queryRoots(rootColumns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.close();
- }
-
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 200, "Device", "Storage A", 2000, 0, ""),
new MtpRoot(0, 202, "Device", "Storage C", 2002, 0, "")
});
@@ -334,21 +323,6 @@
cursor.close();
}
- {
- final Cursor cursor = mDatabase.queryRoots(rootColumns);
- assertEquals(3, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(1001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.close();
- }
-
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
{
@@ -364,18 +338,6 @@
assertEquals("Device Storage C", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
}
-
- {
- final Cursor cursor = mDatabase.queryRoots(rootColumns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(2002, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.close();
- }
}
public void testRestoreIdForChildDocuments() throws Exception {
@@ -461,26 +423,33 @@
Root.COLUMN_ROOT_ID,
Root.COLUMN_AVAILABLE_BYTES
};
- mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
- mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
- mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
- new MtpRoot(0, 100, "Device", "Storage", 0, 0, "")
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0]));
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+ new MtpRoot(0, 100, "Device A", "Storage", 0, 0, "")
});
- mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
- new MtpRoot(1, 100, "Device", "Storage", 0, 0, "")
+ mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] {
+ new MtpRoot(1, 100, "Device B", "Storage", 0, 0, "")
});
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
- assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+ assertEquals("Device A Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
- assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
+ assertEquals("Device B Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
}
@@ -488,36 +457,36 @@
final Cursor cursor = mDatabase.queryRoots(rootColumns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(3, getInt(cursor, Root.COLUMN_ROOT_ID));
assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(4, getInt(cursor, Root.COLUMN_ROOT_ID));
assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.close();
}
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("deviceDocIdA");
- mDatabase.getMapper().startAddingDocuments("deviceDocIdB");
- mDatabase.getMapper().putRootDocuments("deviceDocIdA", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().startAddingDocuments("2");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 200, "Device", "Storage", 2000, 0, "")
});
- mDatabase.getMapper().putRootDocuments("deviceDocIdB", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("2", resources, new MtpRoot[] {
new MtpRoot(1, 300, "Device", "Storage", 3000, 0, "")
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocIdA");
- mDatabase.getMapper().stopAddingDocuments("deviceDocIdB");
+ mDatabase.getMapper().stopAddingDocuments("1");
+ mDatabase.getMapper().stopAddingDocuments("2");
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -527,10 +496,10 @@
final Cursor cursor = mDatabase.queryRoots(rootColumns);
assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(5, getInt(cursor, Root.COLUMN_ROOT_ID));
assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(6, getInt(cursor, Root.COLUMN_ROOT_ID));
assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.close();
}
@@ -591,29 +560,34 @@
Root.COLUMN_AVAILABLE_BYTES
};
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", false, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
});
mDatabase.getMapper().clearMapping();
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 300, "Device", "Storage", 3000, 0, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
{
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -622,7 +596,7 @@
final Cursor cursor = mDatabase.queryRoots(rootColumns);
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.close();
}
@@ -634,19 +608,15 @@
MtpDatabaseConstants.COLUMN_STORAGE_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME
};
- final String[] rootColumns = new String[] {
- Root.COLUMN_ROOT_ID,
- Root.COLUMN_AVAILABLE_BYTES
- };
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 200, "Device", "Storage", 2000, 0, ""),
new MtpRoot(0, 201, "Device", "Storage", 2001, 0, ""),
});
@@ -665,33 +635,27 @@
assertEquals("Device Storage", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
}
- {
- final Cursor cursor = mDatabase.queryRoots(rootColumns);
- assertEquals(2, cursor.getCount());
- cursor.moveToNext();
- assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.moveToNext();
- assertEquals(3, getInt(cursor, Root.COLUMN_ROOT_ID));
- assertEquals(2001, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
- cursor.close();
- }
}
public void testReplaceExistingRoots() {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
// The client code should be able to replace existing rows with new information.
// Add one.
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
// Replace it.
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage B", 1000, 1000, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
{
final String[] columns = new String[] {
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
@@ -701,7 +665,7 @@
final Cursor cursor = mDatabase.queryRootDocuments(columns);
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, COLUMN_DOCUMENT_ID));
+ assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID));
assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID));
assertEquals("Device Storage B", getString(cursor, COLUMN_DISPLAY_NAME));
cursor.close();
@@ -709,12 +673,14 @@
{
final String[] columns = new String[] {
Root.COLUMN_ROOT_ID,
+ Root.COLUMN_TITLE,
Root.COLUMN_AVAILABLE_BYTES
};
final Cursor cursor = mDatabase.queryRoots(columns);
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID));
+ assertEquals("Device Storage B", getString(cursor, Root.COLUMN_TITLE));
assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES));
cursor.close();
}
@@ -723,8 +689,13 @@
public void testFailToReplaceExisitingUnmappedRoots() {
// The client code should not be able to replace rows before resolving 'unmapped' rows.
// Add one.
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
mDatabase.getMapper().clearMapping();
@@ -732,18 +703,19 @@
assertEquals(1, oldCursor.getCount());
// Add one.
- mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 101, "Device", "Storage B", 1000, 1000, ""),
});
// Add one more before resolving unmapped documents.
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
new MtpRoot(0, 102, "Device", "Storage B", 1000, 1000, ""),
});
- mDatabase.getMapper().stopAddingDocuments("deviceDocId");
+ mDatabase.getMapper().stopAddingDocuments("1");
// Because the roots shares the same name, the roots should have new IDs.
- final Cursor newCursor = mDatabase.queryRoots(strings(Root.COLUMN_ROOT_ID));
+ final Cursor newCursor = mDatabase.queryChildDocuments(
+ strings(Document.COLUMN_DOCUMENT_ID), "1");
assertEquals(2, newCursor.getCount());
oldCursor.moveToNext();
newCursor.moveToNext();
@@ -755,9 +727,9 @@
newCursor.close();
}
- public void testQueryDocument() {
+ public void testQueryDocuments() {
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -765,13 +737,61 @@
final Cursor cursor = mDatabase.queryDocument("1", strings(Document.COLUMN_DISPLAY_NAME));
assertEquals(1, cursor.getCount());
cursor.moveToNext();
- assertEquals("Device Storage A", cursor.getString(0));
+ assertEquals("Device Storage A", getString(cursor, Document.COLUMN_DISPLAY_NAME));
cursor.close();
}
+ public void testQueryRoots() {
+ // Add device document.
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(0, "Device", false, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+
+ // It the device does not have storages, it shows a device root.
+ {
+ final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("Device", cursor.getString(0));
+ cursor.close();
+ }
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+ new MtpRoot(0, 100, "Device", "Storage A", 0, 0, "")
+ });
+ mDatabase.getMapper().stopAddingDocuments("1");
+
+ // It the device has single storage, it shows a storage root.
+ {
+ final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("Device Storage A", cursor.getString(0));
+ cursor.close();
+ }
+
+ mDatabase.getMapper().startAddingDocuments("1");
+ mDatabase.getMapper().putStorageDocuments("1", resources, new MtpRoot[] {
+ new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
+ new MtpRoot(0, 101, "Device", "Storage B", 0, 0, "")
+ });
+ mDatabase.getMapper().stopAddingDocuments("1");
+
+ // It the device has multiple storages, it shows a device root.
+ {
+ final Cursor cursor = mDatabase.queryRoots(strings(Root.COLUMN_TITLE));
+ assertEquals(1, cursor.getCount());
+ cursor.moveToNext();
+ assertEquals("Device", cursor.getString(0));
+ cursor.close();
+ }
+ }
+
public void testGetParentId() throws FileNotFoundException {
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -790,7 +810,7 @@
public void testDeleteDocument() {
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -834,7 +854,7 @@
public void testPutNewDocument() {
mDatabase.getMapper().startAddingDocuments("deviceDocId");
- mDatabase.getMapper().putRootDocuments("deviceDocId", resources, new MtpRoot[] {
+ mDatabase.getMapper().putStorageDocuments("deviceDocId", resources, new MtpRoot[] {
new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
});
mDatabase.getMapper().stopAddingDocuments("deviceDocId");
@@ -871,4 +891,12 @@
cursor.close();
}
}
+
+ public void testGetDocumentIdForDevice() {
+ mDatabase.getMapper().startAddingDocuments(null);
+ mDatabase.getMapper().putDeviceDocument(
+ new MtpDeviceRecord(100, "Device", true, new MtpRoot[0]));
+ mDatabase.getMapper().stopAddingDocuments(null);
+ assertEquals("1", mDatabase.getDocumentIdForDevice(100));
+ }
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index b0e9722..71c4897 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -23,7 +23,6 @@
import android.provider.DocumentsContract.Root;
import android.provider.DocumentsContract;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import java.io.FileNotFoundException;
@@ -56,17 +55,20 @@
public void testOpenAndCloseDevice() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mMtpManager.setRoots(0, new MtpRoot[] {
- new MtpRoot(
- 0 /* deviceId */,
- 1 /* storageId */,
- "Device A" /* device model name */,
- "Storage A" /* volume description */,
- 1024 /* free space */,
- 2048 /* total space */,
- "" /* no volume identifier */)
- });
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0,
+ "Device",
+ false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Device A" /* device model name */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ }));
mProvider.openDevice(0);
mResolver.waitForNotification(ROOTS_URI, 1);
@@ -92,57 +94,66 @@
}
// Check if the following notification is the first one or not.
- mMtpManager.addValidDevice(0);
- mMtpManager.setRoots(0, new MtpRoot[] {
- new MtpRoot(
- 0 /* deviceId */,
- 1 /* storageId */,
- "Device A" /* device model name */,
- "Storage A" /* volume description */,
- 1024 /* free space */,
- 2048 /* total space */,
- "" /* no volume identifier */)
- });
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0,
+ "Device",
+ false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Device A" /* device model name */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ }));
mProvider.openDevice(0);
mResolver.waitForNotification(ROOTS_URI, 1);
}
public void testQueryRoots() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mMtpManager.addValidDevice(1);
- mMtpManager.setRoots(0, new MtpRoot[] {
- new MtpRoot(
- 0 /* deviceId */,
- 1 /* storageId */,
- "Device A" /* device model name */,
- "Storage A" /* volume description */,
- 1024 /* free space */,
- 2048 /* total space */,
- "" /* no volume identifier */)
- });
- mMtpManager.setRoots(1, new MtpRoot[] {
- new MtpRoot(
- 1 /* deviceId */,
- 1 /* storageId */,
- "Device B" /* device model name */,
- "Storage B" /* volume description */,
- 2048 /* free space */,
- 4096 /* total space */,
- "Identifier B" /* no volume identifier */)
- });
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 0,
+ "Device",
+ false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 0 /* deviceId */,
+ 1 /* storageId */,
+ "Device A" /* device model name */,
+ "Storage A" /* volume description */,
+ 1024 /* free space */,
+ 2048 /* total space */,
+ "" /* no volume identifier */)
+ }));
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 1,
+ "Device",
+ false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 1 /* deviceId */,
+ 1 /* storageId */,
+ "Device B" /* device model name */,
+ "Storage B" /* volume description */,
+ 2048 /* free space */,
+ 4096 /* total space */,
+ "Identifier B" /* no volume identifier */)
+ }));
{
mProvider.openDevice(0);
mResolver.waitForNotification(ROOTS_URI, 1);
final Cursor cursor = mProvider.queryRoots(null);
- assertEquals(1, cursor.getCount());
+ assertEquals(2, cursor.getCount());
cursor.moveToNext();
- assertEquals("2", cursor.getString(0));
+ assertEquals("3", cursor.getString(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device A Storage A", cursor.getString(3));
- assertEquals("2", cursor.getString(4));
+ assertEquals("3", cursor.getString(4));
assertEquals(1024, cursor.getInt(5));
}
@@ -164,41 +175,50 @@
public void testQueryRoots_error() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mMtpManager.addValidDevice(1);
- // Not set roots for device 0 so that MtpManagerMock#getRoots throws IOException.
- mMtpManager.setRoots(1, new MtpRoot[] {
- new MtpRoot(
- 1 /* deviceId */,
- 1 /* storageId */,
- "Device B" /* device model name */,
- "Storage B" /* volume description */,
- 2048 /* free space */,
- 4096 /* total space */,
- "Identifier B" /* no volume identifier */)
- });
+ mMtpManager.addValidDevice(
+ new MtpDeviceRecord(0, "Device A", false /* unopened */, new MtpRoot[0]));
+ mMtpManager.addValidDevice(new MtpDeviceRecord(
+ 1,
+ "Device",
+ false /* unopened */,
+ new MtpRoot[] {
+ new MtpRoot(
+ 1 /* deviceId */,
+ 1 /* storageId */,
+ "Device B" /* device model name */,
+ "Storage B" /* volume description */,
+ 2048 /* free space */,
+ 4096 /* total space */,
+ "Identifier B" /* no volume identifier */)
+ }));
{
mProvider.openDevice(0);
mProvider.openDevice(1);
mResolver.waitForNotification(ROOTS_URI, 1);
final Cursor cursor = mProvider.queryRoots(null);
- assertEquals(1, cursor.getCount());
+ assertEquals(2, cursor.getCount());
+
cursor.moveToNext();
- assertEquals("2", cursor.getString(0));
+ assertEquals("1", cursor.getString(0));
+ assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
+ assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
+ assertEquals("Device A", cursor.getString(3));
+ assertEquals("1", cursor.getString(4));
+ assertEquals(0, cursor.getInt(5));
+
+ cursor.moveToNext();
+ assertEquals("3", cursor.getString(0));
assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
assertEquals(R.drawable.ic_root_mtp, cursor.getInt(2));
assertEquals("Device B Storage B", cursor.getString(3));
- assertEquals("2", cursor.getString(4));
+ assertEquals("3", cursor.getString(4));
assertEquals(2048, cursor.getInt(5));
}
}
public void testQueryDocument() throws IOException, InterruptedException, TimeoutException {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
-
setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") });
setupDocuments(
0,
@@ -236,9 +256,6 @@
public void testQueryDocument_directory()
throws IOException, InterruptedException, TimeoutException {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
-
setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") });
setupDocuments(
0,
@@ -274,9 +291,6 @@
public void testQueryDocument_forRoot()
throws IOException, InterruptedException, TimeoutException {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
-
setupRoots(0, new MtpRoot[] {
new MtpRoot(
0 /* deviceId */,
@@ -301,9 +315,6 @@
public void testQueryChildDocuments() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
-
setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") });
setupDocuments(
0,
@@ -337,8 +348,6 @@
public void testQueryChildDocuments_cursorError() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
try {
mProvider.queryChildDocuments("1", null, null);
fail();
@@ -349,8 +358,6 @@
public void testQueryChildDocuments_documentError() throws Exception {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") });
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
try {
@@ -363,8 +370,6 @@
public void testDeleteDocument() throws IOException, InterruptedException, TimeoutException {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
setupRoots(0, new MtpRoot[] {
new MtpRoot(0, 0, "Device", "Storage", 0, 0, "")
});
@@ -385,8 +390,6 @@
public void testDeleteDocument_error()
throws IOException, InterruptedException, TimeoutException {
setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
- mMtpManager.addValidDevice(0);
- mProvider.openDevice(0);
setupRoots(0, new MtpRoot[] {
new MtpRoot(0, 0, "Device", "Storage", 0, 0, "")
});
@@ -427,9 +430,11 @@
}
private String[] setupRoots(int deviceId, MtpRoot[] roots)
- throws FileNotFoundException, InterruptedException, TimeoutException {
+ throws InterruptedException, TimeoutException, IOException {
final int changeCount = mResolver.getChangeCount(ROOTS_URI);
- mMtpManager.setRoots(deviceId, roots);
+ mMtpManager.addValidDevice(
+ new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots));
+ mProvider.openDevice(deviceId);
mResolver.waitForNotification(ROOTS_URI, changeCount + 1);
return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID)));
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index ed617e7..5e95e4f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -61,8 +61,9 @@
@Override
public Boolean call() throws IOException {
try {
- mManager.readEvent(mUsbDevice.getDeviceId(), signal);
- return false;
+ while (true) {
+ mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+ }
} catch (OperationCanceledException exception) {
return true;
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index ddc18a4..9a97659 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -19,14 +19,12 @@
import android.content.Context;
import android.mtp.MtpObjectInfo;
import android.os.ParcelFileDescriptor;
+import android.util.SparseArray;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
public class TestMtpManager extends MtpManager {
public static final int CREATED_DOCUMENT_HANDLE = 1000;
@@ -35,9 +33,7 @@
return Arrays.toString(args);
}
- private final Set<Integer> mValidDevices = new HashSet<>();
- private final Set<Integer> mOpenedDevices = new TreeSet<>();
- private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
+ private final SparseArray<MtpDeviceRecord> mDevices = new SparseArray<>();
private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
private final Map<String, int[]> mObjectHandles = new HashMap<>();
private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
@@ -47,18 +43,14 @@
super(context);
}
- void addValidDevice(int deviceId) {
- mValidDevices.add(deviceId);
+ void addValidDevice(MtpDeviceRecord device) {
+ mDevices.put(device.deviceId, device);
}
void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
}
- void setRoots(int deviceId, MtpRoot[] roots) {
- mRoots.put(deviceId, roots);
- }
-
void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
}
@@ -76,28 +68,40 @@
}
@Override
+ MtpDeviceRecord[] getDevices() {
+ final MtpDeviceRecord[] result = new MtpDeviceRecord[mDevices.size()];
+ for (int i = 0; i < mDevices.size(); i++) {
+ final MtpDeviceRecord device = mDevices.valueAt(i);
+ if (device.opened) {
+ result[i] = device;
+ } else {
+ result[i] = new MtpDeviceRecord(
+ device.deviceId, device.name, device.opened, new MtpRoot[0]);
+ }
+ }
+ return result;
+ }
+
+ @Override
void openDevice(int deviceId) throws IOException {
- if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
+ final MtpDeviceRecord device = mDevices.get(deviceId);
+ if (device == null || device.opened) {
throw new IOException();
}
- mOpenedDevices.add(deviceId);
+ mDevices.put(
+ deviceId,
+ new MtpDeviceRecord(device.deviceId, device.name, true, device.roots));
}
@Override
void closeDevice(int deviceId) throws IOException {
- if (!mValidDevices.contains(deviceId) || !mOpenedDevices.contains(deviceId)) {
+ final MtpDeviceRecord device = mDevices.get(deviceId);
+ if (device == null || !device.opened) {
throw new IOException();
}
- mOpenedDevices.remove(deviceId);
- }
-
- @Override
- MtpRoot[] getRoots(int deviceId) throws IOException {
- if (mRoots.containsKey(deviceId)) {
- return mRoots.get(deviceId);
- } else {
- throw new IOException("getRoots error: " + Integer.toString(deviceId));
- }
+ mDevices.put(
+ deviceId,
+ new MtpDeviceRecord(device.deviceId, device.name, false, device.roots));
}
@Override
@@ -189,16 +193,19 @@
@Override
int[] getOpenedDeviceIds() {
- int i = 0;
- final int[] result = new int[mOpenedDevices.size()];
- for (int deviceId : mOpenedDevices) {
- result[i++] = deviceId;
+ final int[] result = new int[mDevices.size()];
+ int count = 0;
+ for (int i = 0; i < mDevices.size(); i++) {
+ final MtpDeviceRecord device = mDevices.valueAt(i);
+ if (device.opened) {
+ result[count++] = device.deviceId;
+ }
}
- return result;
+ return Arrays.copyOf(result, count);
}
@Override
- String getDeviceName(int deviceId) throws IOException {
- return "Device";
+ byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException {
+ return mImportFileBytes.get(pack(deviceId, objectHandle));
}
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index f910321..611e831 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -120,9 +120,19 @@
private static void waitForStorages(
TestResultInstrumentation instrumentation,
MtpManager manager,
- int deviceId) throws IOException, InterruptedException {
+ int deviceId) throws InterruptedException, IOException {
while (true) {
- if (manager.getRoots(deviceId).length == 0) {
+ MtpDeviceRecord device = null;
+ for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
+ if (deviceCandidate.deviceId == deviceId) {
+ device = deviceCandidate;
+ break;
+ }
+ }
+ if (device == null) {
+ throw new IOException("Device was detached.");
+ }
+ if (device.roots.length == 0) {
instrumentation.show("Wait for storages.");
Thread.sleep(1000);
continue;
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 5a6f1d1..af9d251 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -17,9 +17,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.printspooler"
- android:versionName="1"
- android:versionCode="1">
+ package="com.android.printspooler">
<!-- Allows an application to call APIs that give it access to all print jobs
on the device. Usually an app can access only the print jobs it created. -->
@@ -40,6 +38,8 @@
<uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowClearUserData="true"
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/PrintSpooler/res/drawable/ic_info.xml
similarity index 65%
copy from packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
copy to packages/PrintSpooler/res/drawable/ic_info.xml
index f11b690..2ecd1c7 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
+++ b/packages/PrintSpooler/res/drawable/ic_info.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2015 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -14,11 +14,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
+ android:width="24dp"
+ android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF0000FF"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
-</vector>
+ android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"
+ android:fillColor="#757575"/>
+</vector>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index 4381a7a..e0efbc4 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -62,7 +62,7 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 7bc144a..50f44c2 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -38,6 +38,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
+ android:layout_weight="1"
android:duplicateParentState="true">
<TextView
@@ -62,10 +63,20 @@
android:ellipsize="end"
android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorPrimary"
+ android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
</TextView>
</LinearLayout>
+ <ImageView
+ android:id="@+id/more_info"
+ android:layout_width="24dip"
+ android:layout_height="24dip"
+ android:layout_gravity="center_vertical"
+ android:contentDescription="@string/printer_info_desc"
+ android:src="@drawable/ic_info"
+ android:visibility="gone">
+ </ImageView>
+
</LinearLayout>
diff --git a/packages/PrintSpooler/res/values-af/strings.xml b/packages/PrintSpooler/res/values-af/strings.xml
index f263af7..0f34e9e 100644
--- a/packages/PrintSpooler/res/values-af/strings.xml
+++ b/packages/PrintSpooler/res/values-af/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> drukkers gevind</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> drukker gevind</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Meer inligting oor hierdie drukker"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Kies drukdiens"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Soek tans vir drukkers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen drukdienste is geaktiveer nie"</string>
diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml
index a93e0a9..a6e1abf 100644
--- a/packages/PrintSpooler/res/values-am/strings.xml
+++ b/packages/PrintSpooler/res/values-am/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> አታሚዎች ተገኝተዋል</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ተጨማሪ የዚህ አታሚ መረጃ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"የህትመት አገልግሎት ይምረጡ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"አታሚዎችን በመፈለግ ላይ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ምንም የህትመት አገልግሎቶች አልነቁም"</string>
diff --git a/packages/PrintSpooler/res/values-ar/strings.xml b/packages/PrintSpooler/res/values-ar/strings.xml
index c9a6a395..0291b7d 100644
--- a/packages/PrintSpooler/res/values-ar/strings.xml
+++ b/packages/PrintSpooler/res/values-ar/strings.xml
@@ -63,6 +63,8 @@
<item quantity="other">تم العثور على <xliff:g id="COUNT_1">%1$s</xliff:g> من الطابعات</item>
<item quantity="one">تم العثور على طابعة واحدة (<xliff:g id="COUNT_0">%1$s</xliff:g>)</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"مزيد من المعلومات حول هذه الطابعة"</string>
<string name="choose_print_service" msgid="3740309762324459694">"اختر خدمة طباعة"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"البحث عن طابعات"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"لم يتم تمكين أي خدمات طباعة"</string>
diff --git a/packages/PrintSpooler/res/values-az-rAZ/strings.xml b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
index 5aeb7bb..e162793 100644
--- a/packages/PrintSpooler/res/values-az-rAZ/strings.xml
+++ b/packages/PrintSpooler/res/values-az-rAZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer tapıldı</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer tapıldı</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Bu printer haqqında daha ətraflı məlumat"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Çap xidmətini seçin"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printer axtarılır"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Heç bir çap xidməti aktiv edilməyib"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..d6e439c
--- /dev/null
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <string name="app_label" msgid="4469836075319831821">"Štamp. iz memor."</string>
+ <string name="more_options_button" msgid="2243228396432556771">"Još opcija"</string>
+ <string name="label_destination" msgid="9132510997381599275">"Odredište"</string>
+ <string name="label_copies" msgid="3634531042822968308">"Kopije"</string>
+ <string name="label_copies_summary" msgid="3861966063536529540">"Kopija:"</string>
+ <string name="label_paper_size" msgid="908654383827777759">"Veličina papira"</string>
+ <string name="label_paper_size_summary" msgid="5668204981332138168">"Veličina papira:"</string>
+ <string name="label_color" msgid="1108690305218188969">"Boja"</string>
+ <string name="label_duplex" msgid="5370037254347072243">"Dvostrano"</string>
+ <string name="label_orientation" msgid="2853142581990496477">"Položaj"</string>
+ <string name="label_pages" msgid="7768589729282182230">"Stranice"</string>
+ <string name="destination_default_text" msgid="5422708056807065710">"Izaberite štampač"</string>
+ <string name="template_all_pages" msgid="3322235982020148762">"Sve stranice (<xliff:g id="PAGE_COUNT">%1$s</xliff:g>)"</string>
+ <string name="template_page_range" msgid="428638530038286328">"Opseg od <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
+ <string name="pages_range_example" msgid="8558694453556945172">"npr. 1–5, 8, 11–13"</string>
+ <string name="print_preview" msgid="8010217796057763343">"Pregled pre štampanja"</string>
+ <string name="install_for_print_preview" msgid="6366303997385509332">"Instaliraj PDF prikazivač za pregled"</string>
+ <string name="printing_app_crashed" msgid="854477616686566398">"Aplikacija za štampanje je otkazala"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"Generisanje zadatka za štampanje"</string>
+ <string name="save_as_pdf" msgid="5718454119847596853">"Sačuvaj kao PDF"</string>
+ <string name="all_printers" msgid="5018829726861876202">"Svi štampači…"</string>
+ <string name="print_dialog" msgid="32628687461331979">"Dijalog za štampanje"</string>
+ <string name="current_page_template" msgid="1386638343571771292">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>/<xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+ <string name="page_description_template" msgid="6831239682256197161">"<xliff:g id="CURRENT_PAGE">%1$d</xliff:g>. stranica od <xliff:g id="PAGE_COUNT">%2$d</xliff:g>"</string>
+ <string name="summary_template" msgid="8899734908625669193">"Rezime, kopije (<xliff:g id="COPIES">%1$s</xliff:g>), veličina papira <xliff:g id="PAPER_SIZE">%2$s</xliff:g>"</string>
+ <string name="expand_handle" msgid="7282974448109280522">"Regulator za širenje"</string>
+ <string name="collapse_handle" msgid="6886637989442507451">"Regulator za skupljanje"</string>
+ <string name="print_button" msgid="645164566271246268">"Štampaj"</string>
+ <string name="savetopdf_button" msgid="2976186791686924743">"Sačuvaj u PDF-u"</string>
+ <string name="print_options_expanded" msgid="6944679157471691859">"Opcije štampanja su proširene"</string>
+ <string name="print_options_collapsed" msgid="7455930445670414332">"Opcije štampanja su skupljene"</string>
+ <string name="search" msgid="5421724265322228497">"Pretraži"</string>
+ <string name="all_printers_label" msgid="3178848870161526399">"Svi štampači"</string>
+ <string name="add_print_service_label" msgid="5356702546188981940">"Dodaj uslugu"</string>
+ <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Okvir za pretragu je prikazan"</string>
+ <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Okvir za pretragu je sakriven"</string>
+ <string name="print_add_printer" msgid="1088656468360653455">"Dodaj štampač"</string>
+ <string name="print_select_printer" msgid="7388760939873368698">"Izaberi štampač"</string>
+ <string name="print_forget_printer" msgid="5035287497291910766">"Zaboravi štampač"</string>
+ <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
+ <item quantity="one">Pronađen je <xliff:g id="COUNT_1">%1$s</xliff:g> štampač</item>
+ <item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ <item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> štampača</item>
+ </plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Još informacija o ovom štampaču"</string>
+ <string name="choose_print_service" msgid="3740309762324459694">"Izaberite uslugu štampanja"</string>
+ <string name="print_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
+ <string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
+ <string name="print_no_printers" msgid="4869403323900054866">"Nije pronađen nijedan štampač"</string>
+ <string name="printing_notification_title_template" msgid="295903957762447362">"Štampa se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"Otkazuje se <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="failed_notification_title_template" msgid="2256217208186530973">"Greška štampača <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <string name="blocked_notification_title_template" msgid="1175435827331588646">"Štampač je blokirao <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
+ <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780">
+ <item quantity="one">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+ <item quantity="few">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+ <item quantity="other">Zadaci štampanja <xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g></item>
+ </plurals>
+ <string name="cancel" msgid="4373674107267141885">"Otkaži"</string>
+ <string name="restart" msgid="2472034227037808749">"Ponovo pokreni"</string>
+ <string name="no_connection_to_printer" msgid="2159246915977282728">"Nema veze sa štampačem"</string>
+ <string name="reason_unknown" msgid="5507940196503246139">"nepoznato"</string>
+ <string name="printer_unavailable" msgid="2434170617003315690">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> – nedostupan"</string>
+ <string name="print_service_security_warning_title" msgid="2160752291246775320">"Želite li da koristite <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
+ <string name="print_service_security_warning_summary" msgid="1427434625361692006">"Dokument može da prođe kroz jedan ili više servera na putu do štampača."</string>
+ <string-array name="color_mode_labels">
+ <item msgid="7602948745415174937">"Crno-belo"</item>
+ <item msgid="2762241247228983754">"Boja"</item>
+ </string-array>
+ <string-array name="duplex_mode_labels">
+ <item msgid="3882302912790928315">"Ništa"</item>
+ <item msgid="7296563835355641719">"Duga ivica"</item>
+ <item msgid="79513688117503758">"Kratka ivica"</item>
+ </string-array>
+ <string-array name="orientation_labels">
+ <item msgid="4061931020926489228">"Uspravno"</item>
+ <item msgid="3199660090246166812">"Vodoravno"</item>
+ </string-array>
+ <string name="print_write_error_message" msgid="5787642615179572543">"Upisivanje u datoteku nije moguće"</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Žao nam je, ovo nije uspelo. Pokušajte ponovo."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovo"</string>
+ <string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ovaj štampač trenutno nije dostupan."</string>
+ <string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
+</resources>
diff --git a/packages/PrintSpooler/res/values-bg/strings.xml b/packages/PrintSpooler/res/values-bg/strings.xml
index 93feea5..c2393543 100644
--- a/packages/PrintSpooler/res/values-bg/strings.xml
+++ b/packages/PrintSpooler/res/values-bg/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Намерени са <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
<item quantity="one">Намерен е <xliff:g id="COUNT_0">%1$s</xliff:g> принтер</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Още информация за този принтер"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Избиране на услуга за отпечатване"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Търсене на принтери"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Няма активирани услуги за отпечатване"</string>
diff --git a/packages/PrintSpooler/res/values-bn-rBD/strings.xml b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
index 0eed9aa..17a1a35 100644
--- a/packages/PrintSpooler/res/values-bn-rBD/strings.xml
+++ b/packages/PrintSpooler/res/values-bn-rBD/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>টি মুদ্রক খুঁজে পাওয়া গেছে</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"এই মুদ্রকটির বিষয়ে আরো তথ্য"</string>
<string name="choose_print_service" msgid="3740309762324459694">"মুদ্রণ পরিষেবা চয়ন করুন"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"মুদ্রকগুলি অনুসন্ধান করা হচ্ছে"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"মুদ্রণ পরিষেবা সক্ষম নেই"</string>
diff --git a/packages/PrintSpooler/res/values-ca/strings.xml b/packages/PrintSpooler/res/values-ca/strings.xml
index 03d3060..2551206 100644
--- a/packages/PrintSpooler/res/values-ca/strings.xml
+++ b/packages/PrintSpooler/res/values-ca/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">S\'han trobat <xliff:g id="COUNT_1">%1$s</xliff:g> impressores</item>
<item quantity="one">S\'ha trobat <xliff:g id="COUNT_0">%1$s</xliff:g> impressora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Més informació sobre aquesta impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecció del servei d\'impressió"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Cerca d\'impressores"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hi ha cap servei d\'impressió activat"</string>
diff --git a/packages/PrintSpooler/res/values-cs/strings.xml b/packages/PrintSpooler/res/values-cs/strings.xml
index 414abf9..0bb48f8 100644
--- a/packages/PrintSpooler/res/values-cs/strings.xml
+++ b/packages/PrintSpooler/res/values-cs/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Nalezené tiskárny: <xliff:g id="COUNT_1">%1$s</xliff:g></item>
<item quantity="one">Nalezené tiskárny: <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Další informace o této tiskárně"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Zvolte službu tisku"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhledávání tiskáren"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nejsou aktivovány žádné tiskové služby"</string>
diff --git a/packages/PrintSpooler/res/values-da/strings.xml b/packages/PrintSpooler/res/values-da/strings.xml
index 893c991..a9d042b 100644
--- a/packages/PrintSpooler/res/values-da/strings.xml
+++ b/packages/PrintSpooler/res/values-da/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
<item quantity="other">Der blev fundet <xliff:g id="COUNT_1">%1$s</xliff:g> printere</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Flere oplysninger om denne printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Vælg udskriftstjeneste"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søger efter printere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen udskrivningstjenester er aktiveret"</string>
diff --git a/packages/PrintSpooler/res/values-de/strings.xml b/packages/PrintSpooler/res/values-de/strings.xml
index f6f53ea..4eb5d6a9 100644
--- a/packages/PrintSpooler/res/values-de/strings.xml
+++ b/packages/PrintSpooler/res/values-de/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> Drucker gefunden</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> Drucker gefunden</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Weitere Informationen über diesen Drucker"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Druckdienst auswählen"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Suche nach Druckern"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Keine Druckdienste aktiviert"</string>
diff --git a/packages/PrintSpooler/res/values-el/strings.xml b/packages/PrintSpooler/res/values-el/strings.xml
index 10ddf62..cd35785 100644
--- a/packages/PrintSpooler/res/values-el/strings.xml
+++ b/packages/PrintSpooler/res/values-el/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Βρέθηκαν <xliff:g id="COUNT_1">%1$s</xliff:g> εκτυπωτές</item>
<item quantity="one">Βρέθηκε <xliff:g id="COUNT_0">%1$s</xliff:g> εκτυπωτής</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Περισσότερες πληροφορίες σχετικά με αυτόν τον εκτυπωτή"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Επιλέξτε υπηρεσία εκτύπωσης"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Αναζήτηση για εκτυπωτές"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Δεν έχουν ενεργοποιηθεί υπηρεσίες εκτύπωσης"</string>
diff --git a/packages/PrintSpooler/res/values-en-rAU/strings.xml b/packages/PrintSpooler/res/values-en-rAU/strings.xml
index a540ac5..753d9df 100644
--- a/packages/PrintSpooler/res/values-en-rAU/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rAU/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-en-rGB/strings.xml b/packages/PrintSpooler/res/values-en-rGB/strings.xml
index a540ac5..753d9df 100644
--- a/packages/PrintSpooler/res/values-en-rGB/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rGB/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-en-rIN/strings.xml b/packages/PrintSpooler/res/values-en-rIN/strings.xml
index a540ac5..753d9df 100644
--- a/packages/PrintSpooler/res/values-en-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-en-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers found</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer found</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"More information about this printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Choose print service"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Searching for printers"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No print services enabled"</string>
diff --git a/packages/PrintSpooler/res/values-es-rUS/strings.xml b/packages/PrintSpooler/res/values-es-rUS/strings.xml
index 8929aa8..1a0d5d8 100644
--- a/packages/PrintSpooler/res/values-es-rUS/strings.xml
+++ b/packages/PrintSpooler/res/values-es-rUS/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Se encontraron <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras.</item>
<item quantity="one">Se encontró <xliff:g id="COUNT_0">%1$s</xliff:g> impresora.</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Elegir servicio de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
diff --git a/packages/PrintSpooler/res/values-es/strings.xml b/packages/PrintSpooler/res/values-es/strings.xml
index 7cfd92a..eac568d 100644
--- a/packages/PrintSpooler/res/values-es/strings.xml
+++ b/packages/PrintSpooler/res/values-es/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Se han encontrado <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Se ha encontrado <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Más información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Seleccionar servicio de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Buscando impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"No hay servicios de impresión habilitados"</string>
diff --git a/packages/PrintSpooler/res/values-et-rEE/strings.xml b/packages/PrintSpooler/res/values-et-rEE/strings.xml
index ee93bcf..2cde258 100644
--- a/packages/PrintSpooler/res/values-et-rEE/strings.xml
+++ b/packages/PrintSpooler/res/values-et-rEE/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Leiti <xliff:g id="COUNT_1">%1$s</xliff:g> printerit</item>
<item quantity="one">Leiti <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Lisateave selle printeri kohta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Prinditeenuse valimine"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerite otsimine"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ühtegi printimisteenust pole lubatud"</string>
diff --git a/packages/PrintSpooler/res/values-eu-rES/strings.xml b/packages/PrintSpooler/res/values-eu-rES/strings.xml
index 882e888..96a3273 100644
--- a/packages/PrintSpooler/res/values-eu-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-eu-rES/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> inprimagailu aurkitu dira</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> inprimagailu aurkitu da</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Informazio gehiago inprimagailuari buruz"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Aukeratu inprimatze-zerbitzua"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inprimagailuak bilatzen"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ez dago gaituta inprimatzeko zerbitzurik"</string>
diff --git a/packages/PrintSpooler/res/values-fa/strings.xml b/packages/PrintSpooler/res/values-fa/strings.xml
index 10743e7..fdc3989 100644
--- a/packages/PrintSpooler/res/values-fa/strings.xml
+++ b/packages/PrintSpooler/res/values-fa/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> چاپگر یافت شد</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"اطلاعات بیشتر درباره چاپگر"</string>
<string name="choose_print_service" msgid="3740309762324459694">"انتخاب سرویس چاپ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"درحال جستجوی چاپگرها"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"هیچ خدمات چاپی فعال نیست"</string>
diff --git a/packages/PrintSpooler/res/values-fi/strings.xml b/packages/PrintSpooler/res/values-fi/strings.xml
index ee35c41..9267393 100644
--- a/packages/PrintSpooler/res/values-fi/strings.xml
+++ b/packages/PrintSpooler/res/values-fi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> tulostinta löydetty</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> tulostin löydetty</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Lisätietoja tästä tulostimesta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Valitse tulostuspalvelu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Etsitään tulostimia"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ei käytössä olevia tulostuspalveluita"</string>
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index eb99441..bfb4862 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvées</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'information sur cette imprimante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours..."</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
diff --git a/packages/PrintSpooler/res/values-fr/strings.xml b/packages/PrintSpooler/res/values-fr/strings.xml
index c0eecfb..de55e29 100644
--- a/packages/PrintSpooler/res/values-fr/strings.xml
+++ b/packages/PrintSpooler/res/values-fr/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimante trouvée</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> imprimantes trouvées</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plus d\'informations sur cette imprimante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Sélectionner le service d\'impression"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Recherche d\'imprimantes en cours"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Aucun service d\'impression activé"</string>
diff --git a/packages/PrintSpooler/res/values-gl-rES/strings.xml b/packages/PrintSpooler/res/values-gl-rES/strings.xml
index b4a1ec6..dc66084 100644
--- a/packages/PrintSpooler/res/values-gl-rES/strings.xml
+++ b/packages/PrintSpooler/res/values-gl-rES/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Encontráronse <xliff:g id="COUNT_1">%1$s</xliff:g> impresoras</item>
<item quantity="one">Encontrouse <xliff:g id="COUNT_0">%1$s</xliff:g> impresora</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Máis información sobre esta impresora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Escoller servizo de impresión"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Busca de impresoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non hai servizos de impresión activados"</string>
diff --git a/packages/PrintSpooler/res/values-gu-rIN/strings.xml b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
index 8f77953..d05a392 100644
--- a/packages/PrintSpooler/res/values-gu-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-gu-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટર્સ મળ્યાં</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> પ્રિન્ટર્સ મળ્યાં</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"આ પ્રિન્ટર વિશે વધુ માહિતી"</string>
<string name="choose_print_service" msgid="3740309762324459694">"પ્રિન્ટ સેવા પસંદ કરો"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"પ્રિન્ટર્સ માટે શોધી રહ્યું છે"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"કોઈ છાપ સેવાઓ સક્ષમ કરેલ નથી"</string>
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index 4c11323e..8051900 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर मिले</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"इस प्रिंटर के बारे में अधिक जानकारी"</string>
<string name="choose_print_service" msgid="3740309762324459694">"प्रिंट सेवा चुनें"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर खोज रहा है"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोई भी प्रिंट सेवा सक्षम नहीं है"</string>
diff --git a/packages/PrintSpooler/res/values-hr/strings.xml b/packages/PrintSpooler/res/values-hr/strings.xml
index 4cec3ba..4dab4cc 100644
--- a/packages/PrintSpooler/res/values-hr/strings.xml
+++ b/packages/PrintSpooler/res/values-hr/strings.xml
@@ -60,6 +60,8 @@
<item quantity="few">Pronađena su <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
<item quantity="other">Pronađeno je <xliff:g id="COUNT_1">%1$s</xliff:g> pisača</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom pisaču"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Odaberite uslugu ispisa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje pisača"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nije omogućena nijedna usluga ispisa"</string>
diff --git a/packages/PrintSpooler/res/values-hu/strings.xml b/packages/PrintSpooler/res/values-hu/strings.xml
index ac1ba6e..1a56ee7 100644
--- a/packages/PrintSpooler/res/values-hu/strings.xml
+++ b/packages/PrintSpooler/res/values-hu/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> nyomtató észlelve</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> nyomtató észlelve</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"További információ erről a nyomtatóról"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Nyomtatási szolgáltatás kiválasztása"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Nyomtatók keresése"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nincs engedélyezett nyomtatási szolgáltatás"</string>
diff --git a/packages/PrintSpooler/res/values-hy-rAM/strings.xml b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
index dda6745..7b99dcf 100644
--- a/packages/PrintSpooler/res/values-hy-rAM/strings.xml
+++ b/packages/PrintSpooler/res/values-hy-rAM/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
<item quantity="other">Գտնվել է <xliff:g id="COUNT_1">%1$s</xliff:g> տպիչ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Հավելյալ տեղեկություններ այս տպիչի մասին"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Ընտրեք տպելու ծառայությունը"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Տպիչների որոնում"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ակտիվացված տպման ծառայություններ չկան"</string>
diff --git a/packages/PrintSpooler/res/values-in/strings.xml b/packages/PrintSpooler/res/values-in/strings.xml
index b203e2b..a991272 100644
--- a/packages/PrintSpooler/res/values-in/strings.xml
+++ b/packages/PrintSpooler/res/values-in/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printer ditemukan</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer ditemukan</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Informasi selengkapnya tentang printer ini"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pilih layanan cetak"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Tidak ada layanan cetak yang aktif"</string>
diff --git a/packages/PrintSpooler/res/values-is-rIS/strings.xml b/packages/PrintSpooler/res/values-is-rIS/strings.xml
index 6dfdabc..e93f702 100644
--- a/packages/PrintSpooler/res/values-is-rIS/strings.xml
+++ b/packages/PrintSpooler/res/values-is-rIS/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> prentari fannst</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> prentarar fundust</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Frekari upplýsingar um þennan prentara"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Veldu prentþjónustu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Leitar að prentara"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Engin prentþjónusta er virk"</string>
diff --git a/packages/PrintSpooler/res/values-it/strings.xml b/packages/PrintSpooler/res/values-it/strings.xml
index fd5473a..ffba353 100644
--- a/packages/PrintSpooler/res/values-it/strings.xml
+++ b/packages/PrintSpooler/res/values-it/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> stampanti trovate</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> stampante trovata</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Ulteriori informazioni su questa stampante"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Scegli servizio di stampa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ricerca di stampanti"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Non è stato attivato alcun servizio di stampa"</string>
diff --git a/packages/PrintSpooler/res/values-iw/strings.xml b/packages/PrintSpooler/res/values-iw/strings.xml
index dd062a3..2ac1093 100644
--- a/packages/PrintSpooler/res/values-iw/strings.xml
+++ b/packages/PrintSpooler/res/values-iw/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">נמצאו <xliff:g id="COUNT_1">%1$s</xliff:g> מדפסות</item>
<item quantity="one">נמצאה מדפסת <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"מידע נוסף על מדפסת זו"</string>
<string name="choose_print_service" msgid="3740309762324459694">"בחר שירות הדפסה"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"מחפש מדפסות"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"לא הופעלו שירותי הדפסה"</string>
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 23e4809..2c3c24d 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>台のプリンタが見つかりました</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>台のプリンタが見つかりました</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"このプリンタの詳細"</string>
<string name="choose_print_service" msgid="3740309762324459694">"印刷サービスの選択"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"プリンタの検索中"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"使用できる印刷サービスがありません"</string>
diff --git a/packages/PrintSpooler/res/values-ka-rGE/strings.xml b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
index 9f86f05..2b0285d 100644
--- a/packages/PrintSpooler/res/values-ka-rGE/strings.xml
+++ b/packages/PrintSpooler/res/values-ka-rGE/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> პრინტერი ნაპოვნია</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"დამატებითი ინფორმაცია ამ პრინტერის შესახებ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"აირჩიეთ ბეჭდვის სერვისი"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"მიმდინარეობს პრინტერების ძიება"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ბეჭდვის სერვისები გააქტიურებული არ არის"</string>
diff --git a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
index 05c300e..fc099c9 100644
--- a/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
+++ b/packages/PrintSpooler/res/values-kk-rKZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Осы принтер туралы қосымша ақпарат"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Принтер қызметін таңдау"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлерді іздеу"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Басып шығару қызметтері қосылмаған"</string>
diff --git a/packages/PrintSpooler/res/values-km-rKH/strings.xml b/packages/PrintSpooler/res/values-km-rKH/strings.xml
index 0861e59..b51091e 100644
--- a/packages/PrintSpooler/res/values-km-rKH/strings.xml
+++ b/packages/PrintSpooler/res/values-km-rKH/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_1">%1$s</xliff:g></item>
<item quantity="one">រកឃើញម៉ាស៊ីនបោះពុម្ព <xliff:g id="COUNT_0">%1$s</xliff:g></item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ព័ត៌មានបន្ថែមអំពីម៉ាស៊ីបោះពុម្ពនេះ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ជ្រើសសេវាបោះពុម្ព"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ស្វែងរកម៉ាស៊ីនបោះពុម្ព"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"គ្មានការបើកដំណើរការសេវាបោះពុម្ពទេ"</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index 71b098d..5d5dee8 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ಪ್ರಿಂಟರ್ಗಳು ಪತ್ತೆಯಾಗಿವೆ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ಈ ಪ್ರಿಂಟರ್ ಬಗ್ಗೆ ಇನ್ನಷ್ಟು ಮಾಹಿತಿ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ಮುದ್ರಣ ಸೇವೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ಪ್ರಿಂಟರ್ಗಳಿಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ಯಾವುದೇ ಮುದ್ರಣ ಸೇವೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿಲ್ಲ"</string>
diff --git a/packages/PrintSpooler/res/values-ko/strings.xml b/packages/PrintSpooler/res/values-ko/strings.xml
index 451ab58..98617e7 100644
--- a/packages/PrintSpooler/res/values-ko/strings.xml
+++ b/packages/PrintSpooler/res/values-ko/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">프린터 <xliff:g id="COUNT_1">%1$s</xliff:g>대 검색됨</item>
<item quantity="one">프린터 <xliff:g id="COUNT_0">%1$s</xliff:g>대 검색됨</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"이 프린터에 대한 정보 더보기"</string>
<string name="choose_print_service" msgid="3740309762324459694">"인쇄 서비스 선택"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"프린터 검색 중"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"사용 가능한 프린트 서비스 없음"</string>
diff --git a/packages/PrintSpooler/res/values-ky-rKG/strings.xml b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
index 98da08c..2a11ff8 100644
--- a/packages/PrintSpooler/res/values-ky-rKG/strings.xml
+++ b/packages/PrintSpooler/res/values-ky-rKG/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> принтер табылды</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> принтер табылды</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Бул принтер жөнүндө көбүрөөк маалымат"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Принтер кызматын тандоо"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтерлер изделүүдө"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Принтер-кызматтары иштетилген эмес"</string>
diff --git a/packages/PrintSpooler/res/values-lo-rLA/strings.xml b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
index 2029fdf..788e5aa 100644
--- a/packages/PrintSpooler/res/values-lo-rLA/strings.xml
+++ b/packages/PrintSpooler/res/values-lo-rLA/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ເຄື່ອງພິມຖືກພົບແລ້ວ</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ເຄື່ອງພິມຖືກພົບແລ້ວ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ຂໍ້ມູນເພີ່ມເຕີມກ່ຽວກັບເຄື່ອງພິມນີ້"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ເລືອກບໍລິການການພິມ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ກຳລັງຊອກຫາເຄື່ອງພິມ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ບໍ່ມີການບໍລິການພິມເປີດໃຊ້ງານໄວ້"</string>
diff --git a/packages/PrintSpooler/res/values-lt/strings.xml b/packages/PrintSpooler/res/values-lt/strings.xml
index 972abb5..1826e8e 100644
--- a/packages/PrintSpooler/res/values-lt/strings.xml
+++ b/packages/PrintSpooler/res/values-lt/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvo</item>
<item quantity="other">Rasta <xliff:g id="COUNT_1">%1$s</xliff:g> spausdintuvų</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"„<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g>“ – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Daugiau informacijos apie šį spausdintuvą"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pasirinkite spausdinimo paslaugą"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Ieškoma spausdintuvų"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Neįgalinta jokių spausdinimo paslaugų"</string>
diff --git a/packages/PrintSpooler/res/values-lv/strings.xml b/packages/PrintSpooler/res/values-lv/strings.xml
index f565b23..5c17efe 100644
--- a/packages/PrintSpooler/res/values-lv/strings.xml
+++ b/packages/PrintSpooler/res/values-lv/strings.xml
@@ -60,6 +60,8 @@
<item quantity="one">Atrasts <xliff:g id="COUNT_1">%1$s</xliff:g> printers</item>
<item quantity="other">Atrasti <xliff:g id="COUNT_1">%1$s</xliff:g> printeri</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> — <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Plašāka informācija par šo printeri"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Izvēlieties drukāšanas pakalpojumu"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printeru meklēšana"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nav iespējots neviens drukas pakalpojums"</string>
diff --git a/packages/PrintSpooler/res/values-mk-rMK/strings.xml b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
index f5c06d1..ebc1181 100644
--- a/packages/PrintSpooler/res/values-mk-rMK/strings.xml
+++ b/packages/PrintSpooler/res/values-mk-rMK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатач</item>
<item quantity="other">Пронајдени се <xliff:g id="COUNT_1">%1$s</xliff:g> печатачи</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Повеќе информации за овој печатач"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Избери услуга печатење"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пребарување печатачи"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Нема овозможени услуги за печатење"</string>
diff --git a/packages/PrintSpooler/res/values-ml-rIN/strings.xml b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
index 2d45ce5..c08a3d4 100644
--- a/packages/PrintSpooler/res/values-ml-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ml-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> പ്രിന്ററുകൾ കണ്ടെത്തി</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> പ്രിന്റർ കണ്ടെത്തി</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ഈ പ്രിന്ററിനെ കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"പ്രിന്റ് സേവനം തിരഞ്ഞെടുക്കുക"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"പ്രിന്ററുകൾക്കായി തിരയുന്നു"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"പ്രിന്റ് സേവനങ്ങളൊന്നും പ്രവർത്തനക്ഷമാക്കിയിട്ടില്ല"</string>
diff --git a/packages/PrintSpooler/res/values-mn-rMN/strings.xml b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
index f2c7b73..dcef28f0 100644
--- a/packages/PrintSpooler/res/values-mn-rMN/strings.xml
+++ b/packages/PrintSpooler/res/values-mn-rMN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> хэвлэгч олдсон байна</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> хэвлэгч олдсон байна</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Энэ хэвлэгчийн талаарх дэлгэрэнгүй мэдээлэл"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Хэвлэх үйлчилгээг сонгох"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Принтер хайж байна"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Хэвлэх үйлчилгээг идэвхжүүлээгүй"</string>
diff --git a/packages/PrintSpooler/res/values-mr-rIN/strings.xml b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
index 1c079dc..384f0de 100644
--- a/packages/PrintSpooler/res/values-mr-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-mr-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळला</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर आढळले</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"या प्रिंटर विषयी अधिक माहिती"</string>
<string name="choose_print_service" msgid="3740309762324459694">"मुद्रण सेवा निवडा"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिंटर शोधत आहे"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कोणत्याही मुद्रण सेवा सक्षम केलेल्या नाहीत"</string>
diff --git a/packages/PrintSpooler/res/values-ms-rMY/strings.xml b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
index d6b5ea7..19a6e76 100644
--- a/packages/PrintSpooler/res/values-ms-rMY/strings.xml
+++ b/packages/PrintSpooler/res/values-ms-rMY/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> pencetak ditemui</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> pencetak ditemui</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Maklumat lanjut tentang pencetak ini"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pilih perkhidmatan cetak"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Mencari pencetak"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Perkhidmatan cetak tidak didayakan"</string>
diff --git a/packages/PrintSpooler/res/values-my-rMM/strings.xml b/packages/PrintSpooler/res/values-my-rMM/strings.xml
index c3dc490..d3c0672 100644
--- a/packages/PrintSpooler/res/values-my-rMM/strings.xml
+++ b/packages/PrintSpooler/res/values-my-rMM/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> စာထုတ်စက်များ တွေ့ရှိပါသည်</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>စာထုတ်စက် တွေ့ရှိပါသည်</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ဤပရင်တာ အကြောင်း ပိုမိုလေ့လာပါ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"စာထုတ်ရန် ဝန်ဆောင်မှုကို ရွေးချယ်ပါ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"စာထုတ်စက်များကို ရှာနေပါသည်"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ပုံနှိပ်ထုတ်ယူရေး ဝန်ဆောင်မှုများ ဖွင့်မထားပါ"</string>
diff --git a/packages/PrintSpooler/res/values-nb/strings.xml b/packages/PrintSpooler/res/values-nb/strings.xml
index 945bbea..c34e7bc 100644
--- a/packages/PrintSpooler/res/values-nb/strings.xml
+++ b/packages/PrintSpooler/res/values-nb/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivere ble funnet</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skriver ble funnet</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mer informasjon om denne printeren"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Velg utskriftstjeneste"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Søker etter skrivere"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ingen utskriftstjenester er slått på"</string>
diff --git a/packages/PrintSpooler/res/values-ne-rNP/strings.xml b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
index 45bcc95..d1959d9 100644
--- a/packages/PrintSpooler/res/values-ne-rNP/strings.xml
+++ b/packages/PrintSpooler/res/values-ne-rNP/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिन्टरहरू भेटिए</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> प्रिन्टर भेटियो</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"यस प्रिन्टरको बारेमा थप जानकारी"</string>
<string name="choose_print_service" msgid="3740309762324459694">"प्रिन्ट सेवा छनौट गर्नुहोस्"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"प्रिन्टरहरू खोज्दै"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"कुनै पनि मुद्रण सेवाहरू सक्रिय छैनन्"</string>
diff --git a/packages/PrintSpooler/res/values-nl/strings.xml b/packages/PrintSpooler/res/values-nl/strings.xml
index 76c8656..5df3298 100644
--- a/packages/PrintSpooler/res/values-nl/strings.xml
+++ b/packages/PrintSpooler/res/values-nl/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> printers gevonden</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> printer gevonden</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Meer informatie over deze printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Afdrukservice kiezen"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printers zoeken"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Geen afdrukservices ingeschakeld"</string>
diff --git a/packages/PrintSpooler/res/values-pa-rIN/strings.xml b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
index 45fa460..57e9969 100644
--- a/packages/PrintSpooler/res/values-pa-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-pa-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਮਿਲੇ</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ਪ੍ਰਿੰਟਰ ਮਿਲੇ</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ਇਸ ਪ੍ਰਿੰਟਰ ਬਾਰੇ ਹੋਰ ਜਾਣਕਾਰੀ"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ਪ੍ਰਿੰਟ ਸੇਵਾ ਚੁਣੋ"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ਪ੍ਰਿੰਟਰ ਖੋਜ ਰਿਹਾ ਹੈ"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ਪ੍ਰਿੰਟ ਸੇਵਾਵਾਂ ਯੋਗ ਨਹੀਂ ਬਣਾਈਆਂ ਗਈਆਂ"</string>
diff --git a/packages/PrintSpooler/res/values-pl/strings.xml b/packages/PrintSpooler/res/values-pl/strings.xml
index df3ee924..4439acb 100644
--- a/packages/PrintSpooler/res/values-pl/strings.xml
+++ b/packages/PrintSpooler/res/values-pl/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Znaleziono <xliff:g id="COUNT_1">%1$s</xliff:g> drukarki</item>
<item quantity="one">Znaleziono <xliff:g id="COUNT_0">%1$s</xliff:g> drukarkę</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Więcej informacji o tej drukarce"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Wybierz usługę drukowania"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Szukanie drukarek"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Brak włączonych usług drukowania"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rBR/strings.xml b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
index 90da72b..63bb868 100644
--- a/packages/PrintSpooler/res/values-pt-rBR/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rBR/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-pt-rPT/strings.xml b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
index 99bbd81..d364ef4 100644
--- a/packages/PrintSpooler/res/values-pt-rPT/strings.xml
+++ b/packages/PrintSpooler/res/values-pt-rPT/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> impressora encontrada</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações acerca desta impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Escolher o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"A procurar impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-pt/strings.xml b/packages/PrintSpooler/res/values-pt/strings.xml
index 90da72b..63bb868 100644
--- a/packages/PrintSpooler/res/values-pt/strings.xml
+++ b/packages/PrintSpooler/res/values-pt/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> impressoras encontradas</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mais informações sobre essa impressora"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Selecione o serviço de impressão"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Procurando impressoras"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nenhum serviço de impressão ativado"</string>
diff --git a/packages/PrintSpooler/res/values-ro/strings.xml b/packages/PrintSpooler/res/values-ro/strings.xml
index 4cfb8ab..51dfe7a 100644
--- a/packages/PrintSpooler/res/values-ro/strings.xml
+++ b/packages/PrintSpooler/res/values-ro/strings.xml
@@ -60,6 +60,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> de imprimante găsite</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> imprimantă găsită</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mai multe informații despre această imprimantă"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Alegeți serviciul de printare"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Se caută imprimante"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Niciun serviciu de printare activat"</string>
diff --git a/packages/PrintSpooler/res/values-ru/strings.xml b/packages/PrintSpooler/res/values-ru/strings.xml
index fb49330..6ba1046 100644
--- a/packages/PrintSpooler/res/values-ru/strings.xml
+++ b/packages/PrintSpooler/res/values-ru/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Найдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтеров</item>
<item quantity="other">Найдены <xliff:g id="COUNT_1">%1$s</xliff:g> принтера</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Подробные сведения о принтере"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Выберите службу печати"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Поиск принтеров…"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Службы печати недоступны"</string>
diff --git a/packages/PrintSpooler/res/values-si-rLK/strings.xml b/packages/PrintSpooler/res/values-si-rLK/strings.xml
index fb6f145..4908ea5 100644
--- a/packages/PrintSpooler/res/values-si-rLK/strings.xml
+++ b/packages/PrintSpooler/res/values-si-rLK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
<item quantity="other">මුද්රණ යන්ත්ර <xliff:g id="COUNT_1">%1$s</xliff:g> ක් සොයා ගන්නා ලදි</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"මෙම මුද්රණ යන්ත්රය ගැන තවත් තොරතුරු"</string>
<string name="choose_print_service" msgid="3740309762324459694">"මුද්රණ සේවාව තෝරන්න"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"මුද්රණ යන්ත්ර සොයමින්"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"මුද්රණ සේවා සබල නැත"</string>
diff --git a/packages/PrintSpooler/res/values-sk/strings.xml b/packages/PrintSpooler/res/values-sk/strings.xml
index 605237b..418363d 100644
--- a/packages/PrintSpooler/res/values-sk/strings.xml
+++ b/packages/PrintSpooler/res/values-sk/strings.xml
@@ -61,6 +61,8 @@
<item quantity="other">Našlo sa <xliff:g id="COUNT_1">%1$s</xliff:g> tlačiarní</item>
<item quantity="one">Našla sa <xliff:g id="COUNT_0">%1$s</xliff:g> tlačiareň</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Ďalšie informácie o tejto tlačiarni"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Výber tlačovej služby"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Vyhľadávanie tlačiarní"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Žiadne tlačové služby nie sú aktivované"</string>
diff --git a/packages/PrintSpooler/res/values-sl/strings.xml b/packages/PrintSpooler/res/values-sl/strings.xml
index 48d2e1d..e2be161 100644
--- a/packages/PrintSpooler/res/values-sl/strings.xml
+++ b/packages/PrintSpooler/res/values-sl/strings.xml
@@ -61,6 +61,8 @@
<item quantity="few"><xliff:g id="COUNT_1">%1$s</xliff:g> najdeni tiskalniki</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> najdenih tiskalnikov</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Več informacij o tem tiskalniku"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Izberite tiskalno storitev"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Iskanje tiskalnikov"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ni omogočenih tiskalnih storitev"</string>
diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
index 5ba72ff..d5ebf32 100644
--- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml
+++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">U gjetën <xliff:g id="COUNT_1">%1$s</xliff:g> printerë</item>
<item quantity="one">U gjet <xliff:g id="COUNT_0">%1$s</xliff:g> printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Më shumë informacione mbi këtë printer"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Zgjidh shërbimin e printimit"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Po kërkon për printerë"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Nuk ka shërbime printimi të aktivizuara"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 7a04b8d..166e5dd 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -60,6 +60,8 @@
<item quantity="few">Пронађена су <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
<item quantity="other">Пронађено је <xliff:g id="COUNT_1">%1$s</xliff:g> штампача</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Још информација о овом штампачу"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Изаберите услугу штампања"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Претрага штампача"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Ниједна услуга штампања није омогућена"</string>
diff --git a/packages/PrintSpooler/res/values-sv/strings.xml b/packages/PrintSpooler/res/values-sv/strings.xml
index ec4ad30..033d583 100644
--- a/packages/PrintSpooler/res/values-sv/strings.xml
+++ b/packages/PrintSpooler/res/values-sv/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> skrivare hittades</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> skrivare hittades</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Mer information om den här skrivaren"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Välj utskriftstjänst"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Söker efter skrivare"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Inga utskriftstjänster har aktiverats"</string>
diff --git a/packages/PrintSpooler/res/values-sw/strings.xml b/packages/PrintSpooler/res/values-sw/strings.xml
index eed3356..0e2dcdd 100644
--- a/packages/PrintSpooler/res/values-sw/strings.xml
+++ b/packages/PrintSpooler/res/values-sw/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Printa <xliff:g id="COUNT_1">%1$s</xliff:g> zimepatikana</item>
<item quantity="one">Printa <xliff:g id="COUNT_0">%1$s</xliff:g> imepatikana</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Maelezo zaidi kuhusu printa hii"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chagua huduma ya printa"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Inatafuta printa"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Huduma za kuchapisha hazijawashwa"</string>
diff --git a/packages/PrintSpooler/res/values-ta-rIN/strings.xml b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
index a9879c3..2e90d38 100644
--- a/packages/PrintSpooler/res/values-ta-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-ta-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> பிரிண்டர்கள் உள்ளன</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> பிரிண்டர் உள்ளது</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"இந்தப் பிரிண்டர் பற்றிய கூடுதல் தகவல்"</string>
<string name="choose_print_service" msgid="3740309762324459694">"அச்சுப் பொறியைத் தேர்வுசெய்யவும்"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"அச்சுப்பொறிகளைத் தேடுகிறது"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"அச்சுப் பொறிகள் இல்லை"</string>
diff --git a/packages/PrintSpooler/res/values-te-rIN/strings.xml b/packages/PrintSpooler/res/values-te-rIN/strings.xml
index 909cb90..6bdbd5c 100644
--- a/packages/PrintSpooler/res/values-te-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-te-rIN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ప్రింటర్లు కనుగొనబడ్డాయి</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ప్రింటర్ కనుగొనబడింది</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ఈ ప్రింటర్ గురించి మరింత సమాచారం"</string>
<string name="choose_print_service" msgid="3740309762324459694">"ముద్రణ సేవను ఎంచుకోండి"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"ప్రింటర్ల కోసం శోధిస్తోంది"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ముద్రణ సేవలు ఏవీ ప్రారంభించలేదు"</string>
diff --git a/packages/PrintSpooler/res/values-th/strings.xml b/packages/PrintSpooler/res/values-th/strings.xml
index c33a759..a581357 100644
--- a/packages/PrintSpooler/res/values-th/strings.xml
+++ b/packages/PrintSpooler/res/values-th/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">พบเครื่องพิมพ์ <xliff:g id="COUNT_1">%1$s</xliff:g> เครื่อง</item>
<item quantity="one">พบเครื่องพิมพ์ <xliff:g id="COUNT_0">%1$s</xliff:g> เครื่อง</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"ข้อมูลเพิ่มเติมเกี่ยวกับเครื่องพิมพ์นี้"</string>
<string name="choose_print_service" msgid="3740309762324459694">"เลือกบริการพิมพ์"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"กำลังค้นหาเครื่องพิมพ์"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"ไม่ได้เปิดใช้บริการพิมพ์"</string>
diff --git a/packages/PrintSpooler/res/values-tl/strings.xml b/packages/PrintSpooler/res/values-tl/strings.xml
index 545bda4..325ce8c 100644
--- a/packages/PrintSpooler/res/values-tl/strings.xml
+++ b/packages/PrintSpooler/res/values-tl/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> nakitang printer</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> na nakitang printer</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Higit pang impormasyon tungkol sa printer na ito"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Pumili ng serbisyo ng pag-print"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Naghahanap ng mga printer"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Walang mga naka-enable na serbisyo sa pag-print"</string>
diff --git a/packages/PrintSpooler/res/values-tr/strings.xml b/packages/PrintSpooler/res/values-tr/strings.xml
index a13f2df..d945979 100644
--- a/packages/PrintSpooler/res/values-tr/strings.xml
+++ b/packages/PrintSpooler/res/values-tr/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> yazıcı bulundu</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> yazıcı bulundu</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Bu yazıcıyla ilgili daha fazla bilgi"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Yazdırma hizmetini seçin"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Yazıcılar aranıyor"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Etkin yazıcı hizmeti yok"</string>
diff --git a/packages/PrintSpooler/res/values-uk/strings.xml b/packages/PrintSpooler/res/values-uk/strings.xml
index def21ab..ffdfde0 100644
--- a/packages/PrintSpooler/res/values-uk/strings.xml
+++ b/packages/PrintSpooler/res/values-uk/strings.xml
@@ -61,6 +61,8 @@
<item quantity="many">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
<item quantity="other">Знайдено <xliff:g id="COUNT_1">%1$s</xliff:g> принтерів</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Докладніше про цей принтер"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Вибрати службу друку"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук принтерів"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Немає служб друку"</string>
diff --git a/packages/PrintSpooler/res/values-ur-rPK/strings.xml b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
index c031aba..72a6ab9f 100644
--- a/packages/PrintSpooler/res/values-ur-rPK/strings.xml
+++ b/packages/PrintSpooler/res/values-ur-rPK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> پرنٹرز ملے</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> پرنٹر ملا</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"اس پرنٹر کے بارے میں مزید معلومات"</string>
<string name="choose_print_service" msgid="3740309762324459694">"پرنٹ سروس منتخب کریں"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"پرنٹرز تلاش کر رہا ہے"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"کوئی پرنٹ سروس فعال نہیں"</string>
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 59dcca9..c7b4263 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> ta printer topildi</item>
<item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g> ta printer topildi</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Printer haqida batafsil ma’lumot"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chop etish xizmatini tanlang"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Printerlar qidirilmoqda"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Hech qaysi chop etish xizmati yoqilmagan"</string>
diff --git a/packages/PrintSpooler/res/values-vi/strings.xml b/packages/PrintSpooler/res/values-vi/strings.xml
index 0167823..771d57c 100644
--- a/packages/PrintSpooler/res/values-vi/strings.xml
+++ b/packages/PrintSpooler/res/values-vi/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">Đã tìm thấy <xliff:g id="COUNT_1">%1$s</xliff:g> máy in</item>
<item quantity="one">Đã tìm thấy <xliff:g id="COUNT_0">%1$s</xliff:g> máy in</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Thông tin khác về máy in này"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Chọn dịch vụ in"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Đang tìm kiếm máy in"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Chưa kích hoạt dịch vụ in nào"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rCN/strings.xml b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
index a74e994..bea91d7 100644
--- a/packages/PrintSpooler/res/values-zh-rCN/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rCN/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台打印机</item>
<item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台打印机</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"关于此打印机的更多信息"</string>
<string name="choose_print_service" msgid="3740309762324459694">"选择打印服务"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜索打印机"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未启用任何打印服务"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rHK/strings.xml b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
index 35643f3..4fbef0d 100644
--- a/packages/PrintSpooler/res/values-zh-rHK/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rHK/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">已找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 部打印機</item>
<item quantity="one">已找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 部打印機</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"此打印機詳情"</string>
<string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋打印機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"沒有已啟用的列印服務"</string>
diff --git a/packages/PrintSpooler/res/values-zh-rTW/strings.xml b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
index 40c44ff..2fdcaac 100644
--- a/packages/PrintSpooler/res/values-zh-rTW/strings.xml
+++ b/packages/PrintSpooler/res/values-zh-rTW/strings.xml
@@ -59,6 +59,8 @@
<item quantity="other">找到 <xliff:g id="COUNT_1">%1$s</xliff:g> 台印表機</item>
<item quantity="one">找到 <xliff:g id="COUNT_0">%1$s</xliff:g> 台印表機</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"查看這台印表機的詳細資訊"</string>
<string name="choose_print_service" msgid="3740309762324459694">"選擇列印服務"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"正在搜尋印表機"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"未啟用任何列印服務"</string>
diff --git a/packages/PrintSpooler/res/values-zu/strings.xml b/packages/PrintSpooler/res/values-zu/strings.xml
index e0f6f34..92595aa 100644
--- a/packages/PrintSpooler/res/values-zu/strings.xml
+++ b/packages/PrintSpooler/res/values-zu/strings.xml
@@ -59,6 +59,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> amaphrinta atholakele</item>
</plurals>
+ <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
+ <string name="printer_info_desc" msgid="7181988788991581654">"Olunye ulwazi mayelana nale phrinta"</string>
<string name="choose_print_service" msgid="3740309762324459694">"Khetha isevisi yephrinta"</string>
<string name="print_searching_for_printers" msgid="6550424555079932867">"Isesha amaphrinta"</string>
<string name="print_no_print_services" msgid="8561247706423327966">"Amasevisi ephrinta akavuliwe."</string>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 6d81788..b662c58 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -144,6 +144,12 @@
<item quantity="other"><xliff:g id="count" example="2">%1$s</xliff:g> printers found</item>
</plurals>
+ <!-- Template for an extended description of a printer. [CHAR LIMIT=50] -->
+ <string name="printer_extended_description_template"><xliff:g id="print_service_label" example="Canon Print Service">%1$s</xliff:g> - <xliff:g id="printer_description" example="Printer under the stairs">%2$s</xliff:g></string>
+
+ <!-- Description of printer info icon. [CHAR LIMIT=50] -->
+ <string name="printer_info_desc">More information about this printer</string>
+
<!-- Add printer dialog -->
<!-- Title for the alert dialog for selecting a print service. [CHAR LIMIT=50] -->
@@ -172,12 +178,6 @@
<!-- Template for the notification label for a blocked print job. [CHAR LIMIT=25] -->
<string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string>
- <!-- Template for the notification label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] -->
- <plurals name="composite_notification_title_template">
- <item quantity="one"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print job</item>
- <item quantity="other"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print jobs</item>
- </plurals>
-
<!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] -->
<string name="cancel">Cancel</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
new file mode 100644
index 0000000..7274268
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/CustomPrinterIconCache.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.printspooler.model;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.drawable.Icon;
+import android.print.PrinterId;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A fixed size cache for custom printer icons. Old icons get removed with a last recently used
+ * policy.
+ */
+public class CustomPrinterIconCache {
+
+ private final static String LOG_TAG = "CustomPrinterIconCache";
+
+ /** Maximum number of icons in the cache */
+ private final static int MAX_SIZE = 1024;
+
+ /** Directory used to persist state and icons */
+ private final File mCacheDirectory;
+
+ /**
+ * Create a new icon cache.
+ */
+ public CustomPrinterIconCache(@NonNull File cacheDirectory) {
+ mCacheDirectory = new File(cacheDirectory, "icons");
+ if (!mCacheDirectory.exists()) {
+ mCacheDirectory.mkdir();
+ }
+ }
+
+ /**
+ * Return the file name to be used for the icon of a printer
+ *
+ * @param printerId the id of the printer
+ *
+ * @return The file to be used for the icon of the printer
+ */
+ private @Nullable File getIconFileName(@NonNull PrinterId printerId) {
+ StringBuffer sb = new StringBuffer(printerId.getServiceName().getPackageName());
+ sb.append("-");
+
+ try {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update(
+ (printerId.getServiceName().getClassName() + ":" + printerId.getLocalId())
+ .getBytes("UTF-16"));
+ sb.append(String.format("%#040x", new java.math.BigInteger(1, md.digest())));
+ } catch (UnsupportedEncodingException|NoSuchAlgorithmException e) {
+ Log.e(LOG_TAG, "Could not compute custom printer icon file name", e);
+ return null;
+ }
+
+ return new File(mCacheDirectory, sb.toString());
+ }
+
+ /**
+ * Get the {@link Icon} to be used as a custom icon for the printer. If not available request
+ * the icon to be loaded.
+ *
+ * @param printerId the printer the icon belongs to
+ * @return the {@link Icon} if already available or null if icon is not loaded yet
+ */
+ public synchronized @Nullable Icon getIcon(@NonNull PrinterId printerId) {
+ Icon icon;
+
+ File iconFile = getIconFileName(printerId);
+ if (iconFile != null && iconFile.exists()) {
+ try (FileInputStream is = new FileInputStream(iconFile)) {
+ icon = Icon.createFromStream(is);
+ } catch (IOException e) {
+ icon = null;
+ Log.e(LOG_TAG, "Could not read icon from " + iconFile, e);
+ }
+
+ // Touch file so that it is the not likely to be removed
+ iconFile.setLastModified(System.currentTimeMillis());
+ } else {
+ icon = null;
+ }
+
+ return icon;
+ }
+
+ /**
+ * Remove old icons so that only between numFilesToKeep and twice as many icons are left.
+ *
+ * @param numFilesToKeep the number of icons to keep
+ */
+ public void removeOldFiles(int numFilesToKeep) {
+ File files[] = mCacheDirectory.listFiles();
+
+ // To reduce the number of shrink operations, let the cache grow to twice the max size
+ if (files.length > numFilesToKeep * 2) {
+ SortedMap<Long, File> sortedFiles = new TreeMap<>();
+
+ for (File f : files) {
+ sortedFiles.put(f.lastModified(), f);
+ }
+
+ while (sortedFiles.size() > numFilesToKeep) {
+ sortedFiles.remove(sortedFiles.firstKey());
+ }
+ }
+ }
+
+ /**
+ * Handle that a custom icon for a printer was loaded
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ */
+ public synchronized void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+ @Nullable Icon icon) {
+ File iconFile = getIconFileName(printerId);
+
+ if (iconFile == null) {
+ return;
+ }
+
+ try (FileOutputStream os = new FileOutputStream(iconFile)) {
+ icon.writeToStream(os);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write icon for " + printerId + " to storage", e);
+ }
+
+ removeOldFiles(MAX_SIZE);
+ }
+
+ /**
+ * Clear all persisted and non-persisted state from this cache.
+ */
+ public synchronized void clear() {
+ for (File f : mCacheDirectory.listFiles()) {
+ f.delete();
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 82fd512..0210693 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -40,6 +40,7 @@
import android.print.PrintJobInfo;
import android.print.PrintManager;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.Log;
import com.android.printspooler.R;
@@ -61,13 +62,22 @@
private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
+ private static final String PRINT_JOB_NOTIFICATION_GROUP_KEY = "PRINT_JOB_NOTIFICATIONS";
+ private static final String PRINT_JOB_NOTIFICATION_SUMMARY = "PRINT_JOB_NOTIFICATIONS_SUMMARY";
+
private final Context mContext;
private final NotificationManager mNotificationManager;
+ /**
+ * Mapping from printJobIds to their notification Ids.
+ */
+ private final ArraySet<PrintJobId> mNotifications;
+
public NotificationController(Context context) {
mContext = context;
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotifications = new ArraySet<>(0);
}
public void onUpdateNotifications(List<PrintJobInfo> printJobs) {
@@ -81,16 +91,44 @@
}
}
- updateNotification(notifyPrintJobs);
+ updateNotifications(notifyPrintJobs);
}
- private void updateNotification(List<PrintJobInfo> printJobs) {
- if (printJobs.size() <= 0) {
- removeNotification();
- } else if (printJobs.size() == 1) {
- createSimpleNotification(printJobs.get(0));
- } else {
+ /**
+ * Update notifications for the given print jobs, remove all other notifications.
+ *
+ * @param printJobs The print job that we want to create notifications for.
+ */
+ private void updateNotifications(List<PrintJobInfo> printJobs) {
+ ArraySet<PrintJobId> removedPrintJobs = new ArraySet<>(mNotifications);
+
+ final int numPrintJobs = printJobs.size();
+
+ // Create summary notification
+ if (numPrintJobs > 1) {
createStackedNotification(printJobs);
+ } else {
+ mNotificationManager.cancel(PRINT_JOB_NOTIFICATION_SUMMARY, 0);
+ }
+
+ // Create per print job notification
+ for (int i = 0; i < numPrintJobs; i++) {
+ PrintJobInfo printJob = printJobs.get(i);
+ PrintJobId printJobId = printJob.getId();
+
+ removedPrintJobs.remove(printJobId);
+ mNotifications.add(printJobId);
+
+ createSimpleNotification(printJob);
+ }
+
+ // Remove notifications for print jobs that do not exist anymore
+ final int numRemovedPrintJobs = removedPrintJobs.size();
+ for (int i = 0; i < numRemovedPrintJobs; i++) {
+ PrintJobId removedPrintJob = removedPrintJobs.valueAt(i);
+
+ mNotificationManager.cancel(removedPrintJob.flattenToString(), 0);
+ mNotifications.remove(removedPrintJob);
}
}
@@ -148,7 +186,8 @@
.setOngoing(true)
.setShowWhen(true)
.setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ com.android.internal.R.color.system_notification_accent_color))
+ .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY);
if (firstAction != null) {
builder.addAction(firstAction);
@@ -158,11 +197,14 @@
builder.addAction(secondAction);
}
- if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+ if (printJob.getState() == PrintJobInfo.STATE_STARTED
+ || printJob.getState() == PrintJobInfo.STATE_QUEUED) {
float progress = printJob.getProgress();
if (progress >= 0) {
- builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+ builder.setProgress(Integer.MAX_VALUE, (int) (Integer.MAX_VALUE * progress),
false);
+ } else {
+ builder.setProgress(Integer.MAX_VALUE, 0, true);
}
}
@@ -173,7 +215,7 @@
builder.setContentText(printJob.getPrinterName());
}
- mNotificationManager.notify(0, builder.build());
+ mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build());
}
private void createPrintingNotification(PrintJobInfo printJob) {
@@ -201,33 +243,36 @@
.setContentIntent(createContentIntent(null))
.setWhen(System.currentTimeMillis())
.setOngoing(true)
- .setShowWhen(true);
+ .setShowWhen(true)
+ .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY)
+ .setGroupSummary(true);
final int printJobCount = printJobs.size();
InboxStyle inboxStyle = new InboxStyle();
- inboxStyle.setBigContentTitle(String.format(mContext.getResources().getQuantityText(
- R.plurals.composite_notification_title_template,
- printJobCount).toString(), printJobCount));
+ int icon = com.android.internal.R.drawable.ic_print;
for (int i = printJobCount - 1; i>= 0; i--) {
PrintJobInfo printJob = printJobs.get(i);
- if (i == printJobCount - 1) {
- builder.setLargeIcon(((BitmapDrawable) mContext.getResources().getDrawable(
- computeNotificationIcon(printJob), null)).getBitmap());
- builder.setSmallIcon(computeNotificationIcon(printJob));
- builder.setContentTitle(computeNotificationTitle(printJob));
- builder.setContentText(printJob.getPrinterName());
- }
+
inboxStyle.addLine(computeNotificationTitle(printJob));
+
+ // if any print job is in an error state show an error icon for the summary
+ if (printJob.getState() == PrintJobInfo.STATE_FAILED
+ || printJob.getState() == PrintJobInfo.STATE_BLOCKED) {
+ icon = com.android.internal.R.drawable.ic_print_error;
+ }
}
+ builder.setSmallIcon(icon);
+ builder.setLargeIcon(
+ ((BitmapDrawable) mContext.getResources().getDrawable(icon, null)).getBitmap());
builder.setNumber(printJobCount);
builder.setStyle(inboxStyle);
builder.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color));
- mNotificationManager.notify(0, builder.build());
+ mNotificationManager.notify(PRINT_JOB_NOTIFICATION_SUMMARY, 0, builder.build());
}
private String computeNotificationTitle(PrintJobInfo printJob) {
@@ -261,10 +306,6 @@
}
}
- private void removeNotification() {
- mNotificationManager.cancel(0);
- }
-
private PendingIntent createContentIntent(PrintJobId printJobId) {
Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
if (printJobId != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index ea6281d..ac97ad0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -116,6 +116,7 @@
});
return;
}
+ mCloseGuard.close();
mState = STATE_DESTROYED;
if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 90eef83..18160ff 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -23,6 +23,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.graphics.drawable.Icon;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
@@ -109,6 +110,9 @@
private NotificationController mNotificationController;
+ /** Cache for custom printer icons loaded from the print service */
+ private CustomPrinterIconCache mCustomIconCache;
+
public static PrintSpoolerService peekInstance() {
synchronized (sLock) {
return sInstance;
@@ -123,6 +127,7 @@
mPersistanceManager = new PersistenceManager();
mNotificationController = new NotificationController(PrintSpoolerService.this);
+ mCustomIconCache = new CustomPrinterIconCache(getCacheDir());
synchronized (mLock) {
mPersistanceManager.readStateLocked();
@@ -135,6 +140,11 @@
}
@Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
public IBinder onBind(Intent intent) {
return new PrintSpooler();
}
@@ -703,6 +713,37 @@
}.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+ mCustomIconCache.onCustomPrinterIconLoaded(printerId, icon);
+ }
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ return mCustomIconCache.getIcon(printerId);
+ }
+
+ /**
+ * Clear the custom printer icon cache.
+ */
+ public void clearCustomPrinterIconCache() {
+ mCustomIconCache.clear();
+ }
+
private final class PersistenceManager {
private static final String PERSIST_FILE_NAME = "print_spooler_state.xml";
@@ -1262,7 +1303,7 @@
}
private void expect(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (!accept(parser, type, tag)) {
throw new XmlPullParserException("Exepected event: " + type
+ " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -1279,7 +1320,7 @@
}
private boolean accept(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (parser.getEventType() != type) {
return false;
}
@@ -1375,9 +1416,9 @@
}
@Override
- public void removeApprovedPrintService(ComponentName serviceToRemove) {
+ public void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) {
(new ApprovedPrintServices(PrintSpoolerService.this))
- .removeApprovedService(serviceToRemove);
+ .pruneApprovedServices(servicesToKeep);
}
@Override
@@ -1395,5 +1436,38 @@
public PrintSpoolerService getService() {
return PrintSpoolerService.this;
}
+
+ @Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon,
+ IPrintSpoolerCallbacks callbacks, int sequence)
+ throws RemoteException {
+ try {
+ PrintSpoolerService.this.onCustomPrinterIconLoaded(printerId, icon);
+ } finally {
+ callbacks.onCustomPrinterIconCached(sequence);
+ }
+ }
+
+ @Override
+ public void getCustomPrinterIcon(PrinterId printerId, IPrintSpoolerCallbacks callbacks,
+ int sequence) throws RemoteException {
+ Icon icon = null;
+ try {
+ icon = PrintSpoolerService.this.getCustomPrinterIcon(printerId);
+ } finally {
+ callbacks.onGetCustomPrinterIconResult(icon, sequence);
+ }
+ }
+
+ @Override
+ public void clearCustomPrinterIconCache(IPrintSpoolerCallbacks callbacks,
+ int sequence) throws RemoteException {
+ try {
+ PrintSpoolerService.this.clearCustomPrinterIconCache();
+ } finally {
+ callbacks.customPrinterIconCacheCleared(sequence);
+ }
+ }
+
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 1b6e9ce..ea11ae4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -870,7 +870,7 @@
private final MutexFileProvider mFileProvider;
private final IWriteResultCallback mRemoteResultCallback;
- private final CommandDoneCallback mDoneCallback;
+ private final CommandDoneCallback mWriteDoneCallback;
private final Context mContext;
private final Handler mHandler;
@@ -885,7 +885,7 @@
mPageCount = pageCount;
mPages = Arrays.copyOf(pages, pages.length);
mFileProvider = fileProvider;
- mDoneCallback = callback;
+ mWriteDoneCallback = callback;
}
@Override
@@ -997,7 +997,7 @@
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private void handleOnWriteFailed(CharSequence error, int sequence) {
@@ -1015,7 +1015,7 @@
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private void handleOnWriteCanceled(int sequence) {
@@ -1033,7 +1033,7 @@
mCancellation = null;
// Done.
- mDoneCallback.onDone();
+ mWriteDoneCallback.onDone();
}
private final class WriteHandler extends Handler {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index 80c28e0..5525774 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -20,23 +20,33 @@
import android.content.Context;
import android.content.Loader;
import android.content.pm.ServiceInfo;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationRequest;
import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.SystemClock;
import android.print.PrintManager;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
+import android.util.Pair;
import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -49,18 +59,19 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
-import libcore.io.IoUtils;
-
/**
* This class is responsible for loading printers by doing discovery
* and merging the discovered printers with the previously used ones.
*/
-public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
+public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
+ implements LocationListener {
private static final String LOG_TAG = "FusedPrintersProvider";
private static final boolean DEBUG = false;
@@ -70,10 +81,22 @@
private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
+ /** Interval of location updated in ms */
+ private static final int LOCATION_UPDATE_MS = 30 * 1000;
+
+ /** Maximum acceptable age of the location in ms */
+ private static final int MAX_LOCATION_AGE_MS = 10 * 60 * 1000;
+
+ /** The worst accuracy that is considered usable in m */
+ private static final int MIN_LOCATION_ACCURACY = 50;
+
+ /** Maximum distance where a printer is still considered "near" */
+ private static final int MAX_PRINTER_DISTANCE = MIN_LOCATION_ACCURACY * 2;
+
private final List<PrinterInfo> mPrinters =
new ArrayList<>();
- private final List<PrinterInfo> mFavoritePrinters =
+ private final List<Pair<PrinterInfo, Location>> mFavoritePrinters =
new ArrayList<>();
private final PersistenceManager mPersistenceManager;
@@ -84,33 +107,111 @@
private boolean mPrintersUpdatedBefore;
+ /** Last known location, can be null or out of date */
+ private final Object mLocationLock;
+ private Location mLocation;
+
+ /** Location used when the printers were updated the last time */
+ private Location mLocationOfLastPrinterUpdate;
+
+ /** Reference to the system's location manager */
+ private final LocationManager mLocationManager;
+
+ /**
+ * Get a reference to the current location.
+ */
+ private Location getCurrentLocation() {
+ synchronized (mLocationLock) {
+ return mLocation;
+ }
+ }
+
public FusedPrintersProvider(Context context) {
super(context);
+ mLocationLock = new Object();
mPersistenceManager = new PersistenceManager(context);
+ mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
public void addHistoricalPrinter(PrinterInfo printer) {
mPersistenceManager.addPrinterAndWritePrinterHistory(printer);
}
+ /**
+ * Add printer to dest, or if updatedPrinters add the updated printer. If the updated printer
+ * was added, remove it from updatedPrinters.
+ *
+ * @param dest The list the printers should be added to
+ * @param printer The printer to add
+ * @param updatedPrinters The printer to add
+ */
+ private void updateAndAddPrinter(List<PrinterInfo> dest, PrinterInfo printer,
+ Map<PrinterId, PrinterInfo> updatedPrinters) {
+ PrinterInfo updatedPrinter = updatedPrinters.remove(printer.getId());
+ if (updatedPrinter != null) {
+ dest.add(updatedPrinter);
+ } else {
+ dest.add(printer);
+ }
+ }
+
+ /**
+ * Compute the printers, order them appropriately and deliver the printers to the clients. We
+ * prefer printers that have been previously used (favorites) and printers that have been used
+ * previously close to the current location (near printers).
+ *
+ * @param discoveredPrinters All printers currently discovered by the print discovery session.
+ * @param favoritePrinters The ordered list of printers. The earlier in the list, the more
+ * preferred.
+ */
private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters,
- List<PrinterInfo> favoritePrinters) {
+ List<Pair<PrinterInfo, Location>> favoritePrinters) {
List<PrinterInfo> printers = new ArrayList<>();
- // Add the updated favorite printers.
+ // Store the printerIds that have already been added. We cannot compare the printerInfos in
+ // "printers" as they might have been taken from discoveredPrinters and the printerInfo does
+ // not equals() anymore
+ HashSet<PrinterId> alreadyAddedPrinter = new HashSet<>(MAX_FAVORITE_PRINTER_COUNT);
+
+ Location location = getCurrentLocation();
+
+ // Add the favorite printers that have last been used close to the current location
final int favoritePrinterCount = favoritePrinters.size();
- for (int i = 0; i < favoritePrinterCount; i++) {
- PrinterInfo favoritePrinter = favoritePrinters.get(i);
- PrinterInfo updatedPrinter = discoveredPrinters.remove(
- favoritePrinter.getId());
- if (updatedPrinter != null) {
- printers.add(updatedPrinter);
- } else {
- printers.add(favoritePrinter);
+ if (location != null) {
+ for (int i = 0; i < favoritePrinterCount; i++) {
+ // Only add a certain amount of favorite printers
+ if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+ break;
+ }
+
+ PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+ Location printerLocation = favoritePrinters.get(i).second;
+
+ if (printerLocation != null
+ && !alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+ if (printerLocation.distanceTo(location) <= MAX_PRINTER_DISTANCE) {
+ updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
+ alreadyAddedPrinter.add(favoritePrinter.getId());
+ }
+ }
}
}
- // Add other updated printers.
+ // Add the other favorite printers
+ for (int i = 0; i < favoritePrinterCount; i++) {
+ // Only add a certain amount of favorite printers
+ if (printers.size() == MAX_FAVORITE_PRINTER_COUNT) {
+ break;
+ }
+
+ PrinterInfo favoritePrinter = favoritePrinters.get(i).first;
+ if (!alreadyAddedPrinter.contains(favoritePrinter.getId())) {
+ updateAndAddPrinter(printers, favoritePrinter, discoveredPrinters);
+ }
+ }
+
+ // Add other updated printers. Printers that have already been added have been removed from
+ // discoveredPrinters in the calls to updateAndAddPrinter
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = mPrinters.get(i);
@@ -142,6 +243,21 @@
if (DEBUG) {
Log.i(LOG_TAG, "onStartLoading() " + FusedPrintersProvider.this.hashCode());
}
+
+ mLocationManager.requestLocationUpdates(LocationRequest.create()
+ .setQuality(LocationRequest.POWER_LOW).setInterval(LOCATION_UPDATE_MS), this,
+ Looper.getMainLooper());
+
+ Location lastLocation = mLocationManager.getLastLocation();
+ if (lastLocation != null) {
+ onLocationChanged(lastLocation);
+ }
+
+ // Jumpstart location with a single forced update
+ Criteria oneTimeCriteria = new Criteria();
+ oneTimeCriteria.setAccuracy(Criteria.ACCURACY_FINE);
+ mLocationManager.requestSingleUpdate(oneTimeCriteria, this, Looper.getMainLooper());
+
// The contract is that if we already have a valid,
// result the we have to deliver it immediately.
if (!mPrinters.isEmpty()) {
@@ -158,6 +274,8 @@
Log.i(LOG_TAG, "onStopLoading() " + FusedPrintersProvider.this.hashCode());
}
onCancelLoad();
+
+ mLocationManager.removeUpdates(this);
}
@Override
@@ -188,34 +306,38 @@
+ " " + FusedPrintersProvider.this.hashCode());
}
- updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+ getCurrentLocation());
}
});
final int favoriteCount = mFavoritePrinters.size();
List<PrinterId> printerIds = new ArrayList<>(favoriteCount);
for (int i = 0; i < favoriteCount; i++) {
- printerIds.add(mFavoritePrinters.get(i).getId());
+ printerIds.add(mFavoritePrinters.get(i).first.getId());
}
mDiscoverySession.startPrinterDiscovery(printerIds);
List<PrinterInfo> printers = mDiscoverySession.getPrinters();
- if (!printers.isEmpty()) {
- updatePrinters(printers, mFavoritePrinters);
- }
+
+ updatePrinters(printers, mFavoritePrinters, getCurrentLocation());
}
}
- private void updatePrinters(List<PrinterInfo> printers, List<PrinterInfo> favoritePrinters) {
+ private void updatePrinters(List<PrinterInfo> printers,
+ List<Pair<PrinterInfo, Location>> favoritePrinters,
+ Location location) {
if (mPrintersUpdatedBefore && mPrinters.equals(printers)
- && mFavoritePrinters.equals(favoritePrinters)) {
+ && mFavoritePrinters.equals(favoritePrinters)
+ && Objects.equals(mLocationOfLastPrinterUpdate, location)) {
return;
}
+ mLocationOfLastPrinterUpdate = location;
mPrintersUpdatedBefore = true;
// Some of the found printers may have be a printer that is in the
- // history but with its name changed. Hence, we try to update the
- // printer to use its current name instead of the historical one.
- mPersistenceManager.updatePrintersHistoricalNamesIfNeeded(printers);
+ // history but with its properties changed. Hence, we try to update the
+ // printer to use its current properties instead of the historical one.
+ mPersistenceManager.updateHistoricalPrintersIfNeeded(printers);
Map<PrinterId, PrinterInfo> printersMap = new LinkedHashMap<>();
final int printerCount = printers.size();
@@ -271,6 +393,60 @@
onStopLoading();
}
+ /**
+ * Check if the location is acceptable. This is to filter out excessively old or inaccurate
+ * location updates.
+ *
+ * @param location the location to check
+ * @return true iff the location is usable.
+ */
+ private boolean isLocationAcceptable(Location location) {
+ return location != null
+ && location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos()
+ - MAX_LOCATION_AGE_MS * 1000_000L
+ && location.hasAccuracy()
+ && location.getAccuracy() < MIN_LOCATION_ACCURACY;
+ }
+
+ @Override
+ public void onLocationChanged(Location location) {
+ synchronized(mLocationLock) {
+ // We expect the user to not move too fast while printing. Hence prefer more accurate
+ // updates over more recent ones for LOCATION_UPDATE_MS. We add a 10% fudge factor here
+ // as the location provider might send an update slightly too early.
+ if (isLocationAcceptable(location)
+ && !location.equals(mLocation)
+ && (mLocation == null
+ || location
+ .getElapsedRealtimeNanos() > mLocation.getElapsedRealtimeNanos()
+ + LOCATION_UPDATE_MS * 0.9 * 1000_000L
+ || (!mLocation.hasAccuracy()
+ || location.getAccuracy() < mLocation.getAccuracy()))) {
+ // Other callers of updatePrinters might want to know the location, hence cache it
+ mLocation = location;
+
+ if (areHistoricalPrintersLoaded()) {
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters, mLocation);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ // nothing to do
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ // nothing to do
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ // nothing to do
+ }
+
public boolean areHistoricalPrintersLoaded() {
return mPersistenceManager.mReadHistoryCompleted;
}
@@ -294,7 +470,7 @@
public boolean isFavoritePrinter(PrinterId printerId) {
final int printerCount = mFavoritePrinters.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo favoritePritner = mFavoritePrinters.get(i);
+ PrinterInfo favoritePritner = mFavoritePrinters.get(i).first;
if (favoritePritner.getId().equals(printerId)) {
return true;
}
@@ -303,28 +479,22 @@
}
public void forgetFavoritePrinter(PrinterId printerId) {
- List<PrinterInfo> newFavoritePrinters = null;
+ final int favoritePrinterCount = mFavoritePrinters.size();
+ List<Pair<PrinterInfo, Location>> newFavoritePrinters = new ArrayList<>(
+ favoritePrinterCount - 1);
// Remove the printer from the favorites.
- final int favoritePrinterCount = mFavoritePrinters.size();
for (int i = 0; i < favoritePrinterCount; i++) {
- PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
- if (favoritePrinter.getId().equals(printerId)) {
- newFavoritePrinters = new ArrayList<>();
- newFavoritePrinters.addAll(mPrinters);
- newFavoritePrinters.remove(i);
- break;
+ if (!mFavoritePrinters.get(i).first.getId().equals(printerId)) {
+ newFavoritePrinters.add(mFavoritePrinters.get(i));
}
}
- // If we removed a favorite printer, we have work to do.
- if (newFavoritePrinters != null) {
- // Remove the printer from history and persist the latter.
- mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
+ // Remove the printer from history and persist the latter.
+ mPersistenceManager.removeHistoricalPrinterAndWritePrinterHistory(printerId);
- // Recompute and deliver the printers.
- updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters);
- }
+ // Recompute and deliver the printers.
+ updatePrinters(mDiscoverySession.getPrinters(), newFavoritePrinters, getCurrentLocation());
}
private final class PersistenceManager {
@@ -333,18 +503,22 @@
private static final String TAG_PRINTERS = "printers";
private static final String TAG_PRINTER = "printer";
+ private static final String TAG_LOCATION = "location";
private static final String TAG_PRINTER_ID = "printerId";
private static final String ATTR_LOCAL_ID = "localId";
private static final String ATTR_SERVICE_NAME = "serviceName";
+ private static final String ATTR_LONGITUDE = "longitude";
+ private static final String ATTR_LATITUDE = "latitude";
+ private static final String ATTR_ACCURACY = "accuracy";
+
private static final String ATTR_NAME = "name";
private static final String ATTR_DESCRIPTION = "description";
- private static final String ATTR_STATUS = "status";
private final AtomicFile mStatePersistFile;
- private List<PrinterInfo> mHistoricalPrinters = new ArrayList<>();
+ private List<Pair<PrinterInfo, Location>> mHistoricalPrinters = new ArrayList<>();
private boolean mReadHistoryCompleted;
@@ -378,13 +552,13 @@
mReadTask.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
}
- public void updatePrintersHistoricalNamesIfNeeded(List<PrinterInfo> printers) {
+ public void updateHistoricalPrintersIfNeeded(List<PrinterInfo> printers) {
boolean writeHistory = false;
final int printerCount = printers.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = printers.get(i);
- writeHistory |= renamePrinterIfNeeded(printer);
+ writeHistory |= updateHistoricalPrinterIfNeeded(printer);
}
if (writeHistory) {
@@ -392,25 +566,57 @@
}
}
- public boolean renamePrinterIfNeeded(PrinterInfo printer) {
- boolean renamed = false;
+ /**
+ * Updates the historical printer state with the given printer.
+ *
+ * @param printer the printer to update
+ *
+ * @return true iff the historical printer list needs to be updated
+ */
+ public boolean updateHistoricalPrinterIfNeeded(PrinterInfo printer) {
+ boolean writeHistory = false;
final int printerCount = mHistoricalPrinters.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
- if (historicalPrinter.getId().equals(printer.getId())
- && !TextUtils.equals(historicalPrinter.getName(), printer.getName())) {
- mHistoricalPrinters.set(i, printer);
- renamed = true;
+ PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
+
+ if (!historicalPrinter.getId().equals(printer.getId())) {
+ continue;
+ }
+
+ // Overwrite the historical printer with the updated printer as some properties
+ // changed. We ignore the status as this is a volatile state.
+ if (historicalPrinter.equalsIgnoringStatus(printer)) {
+ continue;
+ }
+
+ mHistoricalPrinters.set(i, new Pair<PrinterInfo, Location>(printer,
+ mHistoricalPrinters.get(i).second));
+
+ // We only persist limited information in the printer history, hence check if
+ // we need to persist the update.
+ // @see PersistenceManager.WriteTask#doWritePrinterHistory
+ if (!historicalPrinter.getName().equals(printer.getName())) {
+ if (Objects.equals(historicalPrinter.getDescription(),
+ printer.getDescription())) {
+ writeHistory = true;
+ }
}
}
- return renamed;
+ return writeHistory;
}
public void addPrinterAndWritePrinterHistory(PrinterInfo printer) {
if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
mHistoricalPrinters.remove(0);
}
- mHistoricalPrinters.add(printer);
+
+ Location location = getCurrentLocation();
+ if (!isLocationAcceptable(location)) {
+ location = null;
+ }
+
+ mHistoricalPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
+
writePrinterHistory();
}
@@ -418,7 +624,7 @@
boolean writeHistory = false;
final int printerCount = mHistoricalPrinters.size();
for (int i = printerCount - 1; i >= 0; i--) {
- PrinterInfo historicalPrinter = mHistoricalPrinters.get(i);
+ PrinterInfo historicalPrinter = mHistoricalPrinters.get(i).first;
if (historicalPrinter.getId().equals(printerId)) {
mHistoricalPrinters.remove(i);
writeHistory = true;
@@ -439,63 +645,91 @@
return mLastReadHistoryTimestamp != mStatePersistFile.getBaseFile().lastModified();
}
- private List<PrinterInfo> computeFavoritePrinters(List<PrinterInfo> printers) {
+ /**
+ * Sort the favorite printers by weight. If a printer is in the list multiple times for
+ * different locations, all instances are considered to have the accumulative weight. The
+ * actual favorite printers to display are computed in {@link #computeAndDeliverResult} as
+ * only at this time we know the location to use to determine if a printer is close enough
+ * to be preferred.
+ *
+ * @param printers The printers to sort.
+ * @return The sorted printers.
+ */
+ private List<Pair<PrinterInfo, Location>> sortFavoritePrinters(
+ List<Pair<PrinterInfo, Location>> printers) {
Map<PrinterId, PrinterRecord> recordMap = new ArrayMap<>();
- // Recompute the weights.
+ // Compute the weights.
float currentWeight = 1.0f;
final int printerCount = printers.size();
for (int i = printerCount - 1; i >= 0; i--) {
- PrinterInfo printer = printers.get(i);
- // Aggregate weight for the same printer
- PrinterRecord record = recordMap.get(printer.getId());
+ PrinterId printerId = printers.get(i).first.getId();
+ PrinterRecord record = recordMap.get(printerId);
if (record == null) {
- record = new PrinterRecord(printer);
- recordMap.put(printer.getId(), record);
+ record = new PrinterRecord();
+ recordMap.put(printerId, record);
}
+
+ record.printers.add(printers.get(i));
+
+ // Aggregate weight for the same printer
record.weight += currentWeight;
currentWeight *= WEIGHT_DECAY_COEFFICIENT;
}
- // Soft the favorite printers.
+ // Sort the favorite printers.
List<PrinterRecord> favoriteRecords = new ArrayList<>(
recordMap.values());
Collections.sort(favoriteRecords);
// Write the favorites to the output.
- final int favoriteCount = Math.min(favoriteRecords.size(),
- MAX_FAVORITE_PRINTER_COUNT);
- List<PrinterInfo> favoritePrinters = new ArrayList<>(favoriteCount);
- for (int i = 0; i < favoriteCount; i++) {
- PrinterInfo printer = favoriteRecords.get(i).printer;
- favoritePrinters.add(printer);
+ final int recordCount = favoriteRecords.size();
+ List<Pair<PrinterInfo, Location>> favoritePrinters = new ArrayList<>(printerCount);
+ for (int i = 0; i < recordCount; i++) {
+ favoritePrinters.addAll(favoriteRecords.get(i).printers);
}
return favoritePrinters;
}
+ /**
+ * A set of printers with the same ID and the weight associated with them during
+ * {@link #sortFavoritePrinters}.
+ */
private final class PrinterRecord implements Comparable<PrinterRecord> {
- public final PrinterInfo printer;
+ /**
+ * The printers, all with the same ID, but potentially different properties or locations
+ */
+ public final List<Pair<PrinterInfo, Location>> printers;
+
+ /** The weight associated with the printers */
public float weight;
- public PrinterRecord(PrinterInfo printer) {
- this.printer = printer;
+ /**
+ * Create a new record.
+ */
+ public PrinterRecord() {
+ printers = new ArrayList<>();
}
+ /**
+ * Compare two records by weight.
+ */
@Override
public int compareTo(PrinterRecord another) {
return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
}
}
- private final class ReadTask extends AsyncTask<Void, Void, List<PrinterInfo>> {
+ private final class ReadTask
+ extends AsyncTask<Void, Void, List<Pair<PrinterInfo, Location>>> {
@Override
- protected List<PrinterInfo> doInBackground(Void... args) {
+ protected List<Pair<PrinterInfo, Location>> doInBackground(Void... args) {
return doReadPrinterHistory();
}
@Override
- protected void onPostExecute(List<PrinterInfo> printers) {
+ protected void onPostExecute(List<Pair<PrinterInfo, Location>> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "read history completed "
+ FusedPrintersProvider.this.hashCode());
@@ -518,7 +752,8 @@
final int printerCount = printers.size();
for (int i = printerCount - 1; i >= 0; i--) {
- ComponentName printerServiceName = printers.get(i).getId().getServiceName();
+ ComponentName printerServiceName = printers.get(i).first.getId()
+ .getServiceName();
if (!enabledComponents.contains(printerServiceName)) {
printers.remove(i);
}
@@ -529,12 +764,13 @@
// Compute the favorite printers.
mFavoritePrinters.clear();
- mFavoritePrinters.addAll(computeFavoritePrinters(mHistoricalPrinters));
+ mFavoritePrinters.addAll(sortFavoritePrinters(mHistoricalPrinters));
mReadHistoryCompleted = true;
// Deliver the printers.
- updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters);
+ updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters,
+ getCurrentLocation());
// We are done.
mReadTask = null;
@@ -544,12 +780,12 @@
}
@Override
- protected void onCancelled(List<PrinterInfo> printerInfos) {
+ protected void onCancelled(List<Pair<PrinterInfo, Location>> printerInfos) {
// We are done.
mReadTask = null;
}
- private List<PrinterInfo> doReadPrinterHistory() {
+ private List<Pair<PrinterInfo, Location>> doReadPrinterHistory() {
final FileInputStream in;
try {
in = mStatePersistFile.openRead();
@@ -561,7 +797,7 @@
return new ArrayList<>();
}
try {
- List<PrinterInfo> printers = new ArrayList<>();
+ List<Pair<PrinterInfo, Location>> printers = new ArrayList<>();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(in, StandardCharsets.UTF_8.name());
parseState(parser, printers);
@@ -582,8 +818,9 @@
return Collections.emptyList();
}
- private void parseState(XmlPullParser parser, List<PrinterInfo> outPrinters)
- throws IOException, XmlPullParserException {
+ private void parseState(XmlPullParser parser,
+ List<Pair<PrinterInfo, Location>> outPrinters)
+ throws IOException, XmlPullParserException {
parser.next();
skipEmptyTextTags(parser);
expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS);
@@ -601,8 +838,9 @@
expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS);
}
- private boolean parsePrinter(XmlPullParser parser, List<PrinterInfo> outPrinters)
- throws IOException, XmlPullParserException {
+ private boolean parsePrinter(XmlPullParser parser,
+ List<Pair<PrinterInfo, Location>> outPrinters)
+ throws IOException, XmlPullParserException {
skipEmptyTextTags(parser);
if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) {
return false;
@@ -610,7 +848,6 @@
String name = parser.getAttributeValue(null, ATTR_NAME);
String description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
- final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS));
parser.next();
@@ -625,11 +862,34 @@
expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
parser.next();
- PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
+ skipEmptyTextTags(parser);
+ Location location;
+ if (accept(parser, XmlPullParser.START_TAG, TAG_LOCATION)) {
+ location = new Location("");
+ location.setLongitude(
+ Double.parseDouble(parser.getAttributeValue(null, ATTR_LONGITUDE)));
+ location.setLatitude(
+ Double.parseDouble(parser.getAttributeValue(null, ATTR_LATITUDE)));
+ location.setAccuracy(
+ Float.parseFloat(parser.getAttributeValue(null, ATTR_ACCURACY)));
+ parser.next();
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_LOCATION);
+ parser.next();
+ } else {
+ location = null;
+ }
+
+ // If the printer is available the printer will be replaced by the one read from the
+ // discovery session, hence the only time when this object is used is when the
+ // printer is unavailable.
+ PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name,
+ PrinterInfo.STATUS_UNAVAILABLE);
builder.setDescription(description);
PrinterInfo printer = builder.build();
- outPrinters.add(printer);
+ outPrinters.add(new Pair<PrinterInfo, Location>(printer, location));
if (DEBUG) {
Log.i(LOG_TAG, "[RESTORED] " + printer);
@@ -642,7 +902,7 @@
}
private void expect(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (!accept(parser, type, tag)) {
throw new XmlPullParserException("Exepected event: " + type
+ " and tag: " + tag + " but got event: " + parser.getEventType()
@@ -659,7 +919,7 @@
}
private boolean accept(XmlPullParser parser, int type, String tag)
- throws IOException, XmlPullParserException {
+ throws XmlPullParserException {
if (parser.getEventType() != type) {
return false;
}
@@ -674,14 +934,16 @@
}
}
- private final class WriteTask extends AsyncTask<List<PrinterInfo>, Void, Void> {
+ private final class WriteTask
+ extends AsyncTask<List<Pair<PrinterInfo, Location>>, Void, Void> {
@Override
- protected Void doInBackground(List<PrinterInfo>... printers) {
+ protected Void doInBackground(
+ @SuppressWarnings("unchecked") List<Pair<PrinterInfo, Location>>... printers) {
doWritePrinterHistory(printers[0]);
return null;
}
- private void doWritePrinterHistory(List<PrinterInfo> printers) {
+ private void doWritePrinterHistory(List<Pair<PrinterInfo, Location>> printers) {
FileOutputStream out = null;
try {
out = mStatePersistFile.startWrite();
@@ -693,14 +955,11 @@
final int printerCount = printers.size();
for (int i = 0; i < printerCount; i++) {
- PrinterInfo printer = printers.get(i);
+ PrinterInfo printer = printers.get(i).first;
serializer.startTag(null, TAG_PRINTER);
serializer.attribute(null, ATTR_NAME, printer.getName());
- // Historical printers are always stored as unavailable.
- serializer.attribute(null, ATTR_STATUS, String.valueOf(
- PrinterInfo.STATUS_UNAVAILABLE));
String description = printer.getDescription();
if (description != null) {
serializer.attribute(null, ATTR_DESCRIPTION, description);
@@ -713,6 +972,18 @@
.flattenToString());
serializer.endTag(null, TAG_PRINTER_ID);
+ Location location = printers.get(i).second;
+ if (location != null) {
+ serializer.startTag(null, TAG_LOCATION);
+ serializer.attribute(null, ATTR_LONGITUDE,
+ String.valueOf(location.getLongitude()));
+ serializer.attribute(null, ATTR_LATITUDE,
+ String.valueOf(location.getLatitude()));
+ serializer.attribute(null, ATTR_ACCURACY,
+ String.valueOf(location.getAccuracy()));
+ serializer.endTag(null, TAG_LOCATION);
+ }
+
serializer.endTag(null, TAG_PRINTER);
if (DEBUG) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 2757b81..606f4eb 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -52,7 +52,7 @@
/**
* This class represents the adapter for the pages in the print preview list.
*/
-public final class PageAdapter extends Adapter {
+public final class PageAdapter extends Adapter<ViewHolder> {
private static final String LOG_TAG = "PageAdapter";
private static final int MAX_PREVIEW_PAGES_BATCH = 50;
@@ -409,7 +409,7 @@
- horizontalPaddingAndMargins) / columnCount) + 0.5f);
// Compute max page height.
- final int pageContentDesiredHeight = (int) (((float) pageContentDesiredWidth
+ final int pageContentDesiredHeight = (int) ((pageContentDesiredWidth
/ pageAspectRatio) + 0.5f);
// If the page does not fit entirely in a vertical direction,
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 6521565..9c1cf64 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -30,7 +30,6 @@
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -462,6 +461,7 @@
}
}
+ @Override
public void onUpdateCanceled() {
if (DEBUG) {
Log.i(LOG_TAG, "onUpdateCanceled()");
@@ -1738,8 +1738,9 @@
}
private void updatePageRangeOptions(int pageCount) {
+ @SuppressWarnings("unchecked")
ArrayAdapter<SpinnerItem<Integer>> rangeOptionsSpinnerAdapter =
- (ArrayAdapter) mRangeOptionsSpinner.getAdapter();
+ (ArrayAdapter<SpinnerItem<Integer>>) mRangeOptionsSpinner.getAdapter();
rangeOptionsSpinnerAdapter.clear();
final int[] rangeOptionsValues = getResources().getIntArray(
@@ -1928,6 +1929,7 @@
this.label = label;
}
+ @Override
public String toString() {
return label.toString();
}
@@ -2187,7 +2189,7 @@
if (position == 0 && getPdfPrinter() != null) {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
title = printerHolder.printer.getName();
- icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+ icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == 1) {
title = getString(R.string.all_printers);
}
@@ -2195,20 +2197,16 @@
if (position == 1 && getPdfPrinter() != null) {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
title = printerHolder.printer.getName();
- icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf);
+ icon = getResources().getDrawable(R.drawable.ic_menu_savetopdf, null);
} else if (position == getCount() - 1) {
title = getString(R.string.all_printers);
} else {
PrinterHolder printerHolder = (PrinterHolder) getItem(position);
- title = printerHolder.printer.getName();
- try {
- PackageInfo packageInfo = getPackageManager().getPackageInfo(
- printerHolder.printer.getId().getServiceName().getPackageName(), 0);
- subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
- icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
- } catch (NameNotFoundException nnfe) {
- /* ignore */
- }
+ PrinterInfo printInfo = printerHolder.printer;
+
+ title = printInfo.getName();
+ icon = printInfo.loadIcon(PrintActivity.this);
+ subtitle = printInfo.getDescription();
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index 8716fd2..ce54204 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -78,8 +78,8 @@
mRecyclerView.setLayoutManager(mLayoutManger);
mRecyclerView.setAdapter(mPageAdapter);
mRecyclerView.setItemViewCacheSize(0);
- mPreloadController = new PreloadController(mRecyclerView);
- mRecyclerView.setOnScrollListener(mPreloadController);
+ mPreloadController = new PreloadController();
+ mRecyclerView.addOnScrollListener(mPreloadController);
mContentView = (PrintContentView) activity.findViewById(R.id.options_content);
mEmbeddedContentContainer = (EmbeddedContentContainer) activity.findViewById(
@@ -314,12 +314,9 @@
}
private final class PreloadController extends RecyclerView.OnScrollListener {
- private final RecyclerView mRecyclerView;
-
private int mOldScrollState;
- public PreloadController(RecyclerView recyclerView) {
- mRecyclerView = recyclerView;
+ public PreloadController() {
mOldScrollState = mRecyclerView.getScrollState();
}
@@ -371,7 +368,8 @@
View lastChild = layoutManager.getChildAt(layoutManager.getChildCount() - 1);
ViewHolder lastHolder = mRecyclerView.getChildViewHolder(lastChild);
- return new PageRange(firstHolder.getPosition(), lastHolder.getPosition());
+ return new PageRange(firstHolder.getLayoutPosition(),
+ lastHolder.getLayoutPosition());
}
return null;
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index ab0b2f1..81727ab 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -27,6 +27,7 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -51,6 +52,7 @@
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.widget.AdapterView;
@@ -64,6 +66,7 @@
import android.widget.SearchView;
import android.widget.TextView;
+import com.android.internal.content.PackageMonitor;
import com.android.printspooler.R;
import java.util.ArrayList;
@@ -99,7 +102,8 @@
private AnnounceFilterResult mAnnounceFilterResult;
/** Monitor if new print services get enabled or disabled */
- private ContentObserver mPrintServicesObserver;
+ private ContentObserver mPrintServicesDisabledObserver;
+ private PackageMonitor mPackageObserver;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -243,28 +247,45 @@
* Register listener for changes to the enabled print services.
*/
private void registerServiceMonitor() {
- mPrintServicesObserver = new ContentObserver(new Handler()) {
+ // Listen for services getting disabled
+ mPrintServicesDisabledObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
onPrintServicesUpdate();
}
};
+ // Listen for services getting installed or uninstalled
+ mPackageObserver = new PackageMonitor() {
+ @Override
+ public void onPackageModified(String packageName) {
+ onPrintServicesUpdate();
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ onPrintServicesUpdate();
+ }
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ onPrintServicesUpdate();
+ }
+ };
+
getContentResolver().registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.ENABLED_PRINT_SERVICES), false,
- mPrintServicesObserver);
+ Settings.Secure.getUriFor(Settings.Secure.DISABLED_PRINT_SERVICES), false,
+ mPrintServicesDisabledObserver);
+
+ mPackageObserver.register(this, getMainLooper(), false);
}
/**
- * Unregister {@link #mPrintServicesObserver listener for changes to the enabled print services}
- * or nothing if the listener is not registered.
+ * Unregister the listeners for changes to the enabled print services.
*/
private void unregisterServiceMonitorIfNeeded() {
- if (mPrintServicesObserver != null) {
- getContentResolver().unregisterContentObserver(mPrintServicesObserver);
-
- mPrintServicesObserver = null;
- }
+ getContentResolver().unregisterContentObserver(mPrintServicesDisabledObserver);
+ mPackageObserver.unregister();
}
@Override
@@ -587,20 +608,31 @@
convertView.setEnabled(isActionable(position));
- PrinterInfo printer = (PrinterInfo) getItem(position);
+ final PrinterInfo printer = (PrinterInfo) getItem(position);
CharSequence title = printer.getName();
- CharSequence subtitle = null;
- Drawable icon = null;
+ Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
+ CharSequence printServiceLabel;
try {
- PackageManager pm = getPackageManager();
- PackageInfo packageInfo = pm.getPackageInfo(printer.getId()
- .getServiceName().getPackageName(), 0);
- subtitle = packageInfo.applicationInfo.loadLabel(pm);
- icon = packageInfo.applicationInfo.loadIcon(pm);
- } catch (NameNotFoundException nnfe) {
- /* ignore */
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(
+ printer.getId().getServiceName().getPackageName(), 0);
+
+ printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
+ } catch (NameNotFoundException e) {
+ printServiceLabel = null;
+ }
+
+ CharSequence description = printer.getDescription();
+
+ CharSequence subtitle;
+ if (printServiceLabel == null) {
+ subtitle = description;
+ } else if (description == null) {
+ subtitle = printServiceLabel;
+ } else {
+ subtitle = getString(R.string.printer_extended_description_template,
+ printServiceLabel, description);
}
TextView titleView = (TextView) convertView.findViewById(R.id.title);
@@ -615,6 +647,20 @@
subtitleView.setVisibility(View.GONE);
}
+ ImageView moreInfoView = (ImageView) convertView.findViewById(R.id.more_info);
+ if (printer.getInfoIntent() != null) {
+ moreInfoView.setVisibility(View.VISIBLE);
+ moreInfoView.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ try {
+ startIntentSender(printer.getInfoIntent().getIntentSender(), null, 0, 0, 0);
+ } catch (SendIntentException e) {
+ Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
+ }
+ }
+ });
+ }
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
if (icon != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
index dd10567..a1e3ef4 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java
@@ -23,6 +23,7 @@
import android.printservice.PrintService;
import android.util.ArraySet;
+import java.util.List;
import java.util.Set;
/**
@@ -126,29 +127,27 @@
}
/**
- * If a {@link PrintService} is approved, remove it from the list of approved services.
+ * Remove all approved {@link PrintService print services} that are not in the given set.
*
- * @param serviceToRemove The {@link ComponentName} of the {@link PrintService} to be removed
+ * @param serviceNamesToKeep The {@link ComponentName names } of the services to keep
*/
- public void removeApprovedService(ComponentName serviceToRemove) {
+ public void pruneApprovedServices(List<ComponentName> serviceNamesToKeep) {
synchronized (sLock) {
- if (isApprovedService(serviceToRemove)) {
- // Copy approved services.
- ArraySet<String> approvedServices = new ArraySet<String>(
- mPreferences.getStringSet(APPROVED_SERVICES_PREFERENCE, null));
+ Set<String> approvedServices = getApprovedServices();
+ Set<String> newApprovedServices = new ArraySet<>(approvedServices.size());
+ final int numServiceNamesToKeep = serviceNamesToKeep.size();
+ for(int i = 0; i < numServiceNamesToKeep; i++) {
+ String serviceToKeep = serviceNamesToKeep.get(i).flattenToShortString();
+ if (approvedServices.contains(serviceToKeep)) {
+ newApprovedServices.add(serviceToKeep);
+ }
+ }
+
+ if (approvedServices.size() != newApprovedServices.size()) {
SharedPreferences.Editor editor = mPreferences.edit();
- final int numApprovedServices = approvedServices.size();
- for (int i = 0; i < numApprovedServices; i++) {
- if (approvedServices.valueAt(i)
- .equals(serviceToRemove.flattenToShortString())) {
- approvedServices.removeAt(i);
- break;
- }
- }
-
- editor.putStringSet(APPROVED_SERVICES_PREFERENCE, approvedServices);
+ editor.putStringSet(APPROVED_SERVICES_PREFERENCE, newApprovedServices);
editor.apply();
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index e6613fa..0bb4bfa 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -415,6 +415,7 @@
onDragProgress(progress);
}
+ @Override
public void onViewReleased(View child, float velocityX, float velocityY) {
final int childTop = child.getTop();
@@ -435,14 +436,17 @@
invalidate();
}
+ @Override
public int getOrderedChildIndex(int index) {
return getChildCount() - index - 1;
}
+ @Override
public int getViewVerticalDragRange(View child) {
return mDraggableContent.getHeight();
}
+ @Override
public int clampViewPositionVertical(View child, int top, int dy) {
final int staticOptionBottom = mStaticContent.getBottom();
return Math.max(Math.min(top, getOpenedOptionsY()), getClosedOptionsY());
diff --git a/packages/SettingsLib/res/layout/user_preference.xml b/packages/SettingsLib/res/layout/user_preference.xml
index 75031fd..aa07713 100644
--- a/packages/SettingsLib/res/layout/user_preference.xml
+++ b/packages/SettingsLib/res/layout/user_preference.xml
@@ -23,7 +23,7 @@
android:orientation="horizontal" >
<ImageView
- android:id="@+android:id/icon"
+ android:id="@android:id/icon"
android:layout_width="@dimen/user_icon_view_height"
android:layout_height="@dimen/user_icon_view_height"
android:layout_gravity="center"
@@ -32,12 +32,12 @@
android:paddingTop="@dimen/user_spinner_padding" />
<TextView
- android:id="@+android:id/title"
+ android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:layout_gravity="center"
- android:labelFor="@+android:id/icon"
+ android:labelFor="@android:id/icon"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:paddingStart="@dimen/user_spinner_padding"
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
index c886476..8720eb2 100644
--- a/packages/SettingsLib/res/values-af/arrays.xml
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Gebruik altyd HDCP-kontrolering"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Af"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Af"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per logbuffer"</item>
- <item msgid="2822309747675758628">"256 K per logbuffer"</item>
- <item msgid="6699306198357496731">"1 M per logbuffer"</item>
- <item msgid="5748528643937500349">"4 M per logbuffer"</item>
- <item msgid="1978629051085111592">"16 M per logbuffer"</item>
+ <item msgid="6921048829791179331">"Af"</item>
+ <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+ <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+ <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+ <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+ <item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasie af"</item>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 302ba04..ebe8752 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Maak grootte van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye vensters"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye vensters."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Gedeaktiveer"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altyd aan"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Outomaties"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stel WebView-implementering"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Skakel om na lêerenkripsie"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Skakel om …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Lêerenkripsie is reeds uitgevoer"</string>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
index 324ee83..62e372b 100644
--- a/packages/SettingsLib/res/values-am/arrays.xml
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ሁልጊዜ የHDCP ምልከታ ተጠቀም"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 ኪባ"</item>
- <item msgid="505611754508988476">"256 ኪባ"</item>
- <item msgid="6361286924268716397">"1 ሜባ"</item>
- <item msgid="6405203239560695266">"4 ሜባ"</item>
- <item msgid="3025431211013424097">"16 ሜባ"</item>
+ <item msgid="8665206199209698501">"ጠፍቷል"</item>
+ <item msgid="1593289376502312923">"64 ኪባ"</item>
+ <item msgid="487545340236145324">"256 ኪባ"</item>
+ <item msgid="2423528675294333831">"1 ሜባ"</item>
+ <item msgid="180883774509476541">"4 ሜባ"</item>
+ <item msgid="2803199102589126938">"16 ሜባ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 ኪባ"</item>
- <item msgid="3534782711045262344">"256 ኪባ"</item>
- <item msgid="8085867209202153403">"1 ሜባ"</item>
+ <item msgid="6089470720451068364">"ጠፍቷል"</item>
+ <item msgid="4622460333038586791">"64 ኪባ"</item>
+ <item msgid="2212125625169582330">"256 ኪባ"</item>
+ <item msgid="1704946766699242653">"1 ሜባ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="2822309747675758628">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="6699306198357496731">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="5748528643937500349">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
- <item msgid="1978629051085111592">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="6921048829791179331">"ጠፍቷል"</item>
+ <item msgid="2969458029344750262">"64 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="1342285115665698168">"256 ኪባ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="1314234299552254621">"1 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="3606047780792894151">"4 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
+ <item msgid="5431354956856655120">"16 ሜ በምዝግብ ማስታወሻ ቋጥ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"እነማ ጠፍቷል"</item>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index cd604d2..e33d0fa 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች ዳግም የሚመጣጠኑ እንዲሆኑ ያደርጋቸዋል።"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ለዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃል ለመለወጥ ወይም ለማስወገድ ንካ"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ተሰናክሏል"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ሁልጊዜ ይበራል"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ራስ-ሰር"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"የWebView ትግበራ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"የWebView ትግበራን ያዘጋጁ"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ወደ ፋይል ምሥጠራ ቀይር"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ለውጥ…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ፋይል አስቀድሞ ተመስጥሯል"</string>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
index 654759f..60eebeb 100644
--- a/packages/SettingsLib/res/values-ar/arrays.xml
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"استخدام التحقق من HDCP دومًا"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 كيلوبايت"</item>
- <item msgid="505611754508988476">"256 كيلوبايت"</item>
- <item msgid="6361286924268716397">"1 ميغابايت"</item>
- <item msgid="6405203239560695266">"4 ميغابايت"</item>
- <item msgid="3025431211013424097">"16 ميغابايت"</item>
+ <item msgid="8665206199209698501">"إيقاف"</item>
+ <item msgid="1593289376502312923">"64 كيلوبايت"</item>
+ <item msgid="487545340236145324">"256 كيلوبايت"</item>
+ <item msgid="2423528675294333831">"1 ميغابايت"</item>
+ <item msgid="180883774509476541">"4 ميغابايت"</item>
+ <item msgid="2803199102589126938">"16 ميغابايت"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 كيلوبايت"</item>
- <item msgid="3534782711045262344">"256 كيلوبايت"</item>
- <item msgid="8085867209202153403">"1 ميغابايت"</item>
+ <item msgid="6089470720451068364">"إيقاف"</item>
+ <item msgid="4622460333038586791">"64 كيلوبايت"</item>
+ <item msgid="2212125625169582330">"256 كيلوبايت"</item>
+ <item msgid="1704946766699242653">"1 ميغابايت"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="2822309747675758628">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="6699306198357496731">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="5748528643937500349">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
- <item msgid="1978629051085111592">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="6921048829791179331">"إيقاف"</item>
+ <item msgid="2969458029344750262">"64 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="1342285115665698168">"256 كيلوبايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="1314234299552254621">"1 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="3606047780792894151">"4 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
+ <item msgid="5431354956856655120">"16 ميغابايت لكل ذاكرة تخزين مؤقت للتسجيل"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"إيقاف الرسوم المتحركة"</item>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 7fcfba8..71761b9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"لتمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"كلمة مرور احتياطية للكمبيوتر"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"النسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"المس لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"معطَّل"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"التشغيل دائمًا"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"تلقائيًا"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"تطبيق WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تعيين تطبيق WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"التحويل إلى تشفير ملفات"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تحويل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"تم استخدام تشفير ملفات من قبل"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/arrays.xml b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
index c58b1c6..682b139 100644
--- a/packages/SettingsLib/res/values-az-rAZ/arrays.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Həmişə HDCP yoxlama istifadə edin"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Deaktiv"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Deaktiv"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"hər jurnal buferinə 64K"</item>
- <item msgid="2822309747675758628">"hər jurnal buferinə 256K"</item>
- <item msgid="6699306198357496731">"hər jurnal buferinə 1M"</item>
- <item msgid="5748528643937500349">"hər jurnal buferinə 4M"</item>
- <item msgid="1978629051085111592">"hər jurnal buferinə 16M"</item>
+ <item msgid="6921048829791179331">"Deaktiv"</item>
+ <item msgid="2969458029344750262">"hər jurnal buferinə 64K"</item>
+ <item msgid="1342285115665698168">"hər jurnal buferinə 256K"</item>
+ <item msgid="1314234299552254621">"hər jurnal buferinə 1M"</item>
+ <item msgid="3606047780792894151">"hər jurnal buferinə 4M"</item>
+ <item msgid="5431354956856655120">"hər jurnal buferinə 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasiya deaktiv"</item>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 4c05b27..b5a7181 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bəyannamə dəyərlərindən aslı olmayaraq bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edir."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Sınaq üçün freeform windows aktiv edir"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü rezerv parolu"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstünün tam rezevr kopyalanması üçün parolu dəyişmək və ya silmək üçün toxunun"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Qeyri-aktiv"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Həmişə aktiv"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView icrası"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView icrasını ayarlayın"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Fayl şifrələnməsinə çevirin"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Çevirin..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl artıq şifrələnib"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
new file mode 100644
index 0000000..4715cbf
--- /dev/null
+++ b/packages/SettingsLib/res/values-b+sr+Latn/arrays.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+ <string-array name="wifi_status">
+ <item msgid="1922181315419294640"></item>
+ <item msgid="8934131797783724664">"Skeniranje..."</item>
+ <item msgid="8513729475867537913">"Povezivanje…"</item>
+ <item msgid="515055375277271756">"Potvrđuje se autentičnost..."</item>
+ <item msgid="1943354004029184381">"Preuzimanje IP adrese..."</item>
+ <item msgid="4221763391123233270">"Povezano"</item>
+ <item msgid="624838831631122137">"Obustavljeno"</item>
+ <item msgid="7979680559596111948">"Prekidanje veze..."</item>
+ <item msgid="1634960474403853625">"Veza je prekinuta"</item>
+ <item msgid="746097431216080650">"Neuspešno"</item>
+ <item msgid="6367044185730295334">"Blokirano"</item>
+ <item msgid="503942654197908005">"Privremeno izbegavanje loše veze"</item>
+ </string-array>
+ <string-array name="wifi_status_with_ssid">
+ <item msgid="7714855332363650812"></item>
+ <item msgid="8878186979715711006">"Skeniranje..."</item>
+ <item msgid="355508996603873860">"Povezivanje sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="554971459996405634">"Proveravanje identiteta mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+ <item msgid="7928343808033020343">"Dobijanje IP adrese od mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="8937994881315223448">"Povezano sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1330262655415760617">"Obustavljeno"</item>
+ <item msgid="7698638434317271902">"Prekidanje veze sa mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="197508606402264311">"Veza je prekinuta"</item>
+ <item msgid="8578370891960825148">"Neuspešno"</item>
+ <item msgid="5660739516542454527">"Blokirano"</item>
+ <item msgid="1805837518286731242">"Privremeno izbegavanje loše veze"</item>
+ </string-array>
+ <string-array name="hdcp_checking_titles">
+ <item msgid="441827799230089869">"Nikad ne proveravaj"</item>
+ <item msgid="6042769699089883931">"Potraži samo DRM sadržaj"</item>
+ <item msgid="9174900380056846820">"Uvek proveravaj"</item>
+ </string-array>
+ <string-array name="hdcp_checking_summaries">
+ <item msgid="505558545611516707">"Nikada ne koristi HDCP proveru"</item>
+ <item msgid="3878793616631049349">"Koristi HDCP proveru samo za DRM sadržaj"</item>
+ <item msgid="45075631231212732">"Uvek koristi HDCP proveru"</item>
+ </string-array>
+ <string-array name="select_logd_size_titles">
+ <item msgid="8665206199209698501">"Isključeno"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
+ </string-array>
+ <string-array name="select_logd_size_lowram_titles">
+ <item msgid="6089470720451068364">"Isključeno"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
+ </string-array>
+ <string-array name="select_logd_size_summaries">
+ <item msgid="6921048829791179331">"Isključeno"</item>
+ <item msgid="2969458029344750262">"64 kB po međumemoriji evidencije"</item>
+ <item msgid="1342285115665698168">"256 kB po međumemoriji evidencije"</item>
+ <item msgid="1314234299552254621">"1 MB po međumemoriji evidencije"</item>
+ <item msgid="3606047780792894151">"4 MB po međumemoriji evidencije"</item>
+ <item msgid="5431354956856655120">"16 MB po međumemoriji evidencije"</item>
+ </string-array>
+ <string-array name="window_animation_scale_entries">
+ <item msgid="8134156599370824081">"Animacija je isključena"</item>
+ <item msgid="6624864048416710414">"Razmera animacije 0,5x"</item>
+ <item msgid="2219332261255416635">"Razmera animacije 1x"</item>
+ <item msgid="3544428804137048509">"Razmera animacije 1,5x"</item>
+ <item msgid="3110710404225974514">"Razmera animacije 2x"</item>
+ <item msgid="4402738611528318731">"Razmera animacije 5x"</item>
+ <item msgid="6189539267968330656">"Razmera animacije 10x"</item>
+ </string-array>
+ <string-array name="transition_animation_scale_entries">
+ <item msgid="8464255836173039442">"Animacija je isključena"</item>
+ <item msgid="3375781541913316411">"Razmera animacije 0,5x"</item>
+ <item msgid="1991041427801869945">"Razmera animacije 1x"</item>
+ <item msgid="4012689927622382874">"Razmera animacije 1,5x"</item>
+ <item msgid="3289156759925947169">"Razmera animacije 2x"</item>
+ <item msgid="7705857441213621835">"Razmera animacije 5x"</item>
+ <item msgid="6660750935954853365">"Razmera animacije 10x"</item>
+ </string-array>
+ <string-array name="animator_duration_scale_entries">
+ <item msgid="6039901060648228241">"Animacija je isključena"</item>
+ <item msgid="1138649021950863198">"Razmera animacije 0,5x"</item>
+ <item msgid="4394388961370833040">"Razmera animacije 1x"</item>
+ <item msgid="8125427921655194973">"Razmera animacije 1,5x"</item>
+ <item msgid="3334024790739189573">"Razmera animacije 2x"</item>
+ <item msgid="3170120558236848008">"Razmera animacije 5x"</item>
+ <item msgid="1069584980746680398">"Razmera animacije 10x"</item>
+ </string-array>
+ <string-array name="overlay_display_devices_entries">
+ <item msgid="1606809880904982133">"Nijedno"</item>
+ <item msgid="9033194758688161545">"480 piksela"</item>
+ <item msgid="1025306206556583600">"480 piksela (bezbedno)"</item>
+ <item msgid="1853913333042744661">"720 piksela"</item>
+ <item msgid="3414540279805870511">"720 piksela (bezbedno)"</item>
+ <item msgid="9039818062847141551">"1080 piksela"</item>
+ <item msgid="4939496949750174834">"1080 piksela (bezbedno)"</item>
+ <item msgid="1833612718524903568">"4K"</item>
+ <item msgid="238303513127879234">"4K (bezbedno)"</item>
+ <item msgid="3547211260846843098">"4K (uvećana rezolucija)"</item>
+ <item msgid="5411365648951414254">"4K (uvećana rezolucija, bezbedno)"</item>
+ <item msgid="1311305077526792901">"720 piksela, 1080 piks. (2 ekrana)"</item>
+ </string-array>
+ <string-array name="enable_opengl_traces_entries">
+ <item msgid="3191973083884253830">"Nijedan"</item>
+ <item msgid="9089630089455370183">"Logcat"</item>
+ <item msgid="5397807424362304288">"Systrace (grafika)"</item>
+ <item msgid="1340692776955662664">"Grupno pozivanje funkcije glGetError"</item>
+ </string-array>
+ <string-array name="show_non_rect_clip_entries">
+ <item msgid="993742912147090253">"Isključeno"</item>
+ <item msgid="675719912558941285">"Nacrtaj oblast za isecanje koja nije pravougaonog oblika plavom bojom"</item>
+ <item msgid="1064373276095698656">"Istakni zelenom testirane komande za crtanje"</item>
+ </string-array>
+ <string-array name="track_frame_time_entries">
+ <item msgid="2193584639058893150">"Isključeno"</item>
+ <item msgid="2751513398307949636">"Na ekranu u vidu traka"</item>
+ <item msgid="1851438178120770973">"U adb shell dumpsys gfxinfo"</item>
+ </string-array>
+ <string-array name="debug_hw_overdraw_entries">
+ <item msgid="8190572633763871652">"Isključi"</item>
+ <item msgid="7688197031296835369">"Prikaži oblasti preklapanja"</item>
+ <item msgid="2290859360633824369">"Prikaži oblasti za deuteranomaliju"</item>
+ </string-array>
+ <string-array name="app_process_limit_entries">
+ <item msgid="3401625457385943795">"Standardno ograničenje"</item>
+ <item msgid="4071574792028999443">"Bez pozadinskih procesa"</item>
+ <item msgid="4810006996171705398">"Najviše jedan proces"</item>
+ <item msgid="8586370216857360863">"Najviše dva procesa"</item>
+ <item msgid="836593137872605381">"Najviše tri procesa"</item>
+ <item msgid="7899496259191969307">"Najviše četiri procesa"</item>
+ </string-array>
+ <string-array name="usb_configuration_titles">
+ <item msgid="488237561639712799">"Punjenje"</item>
+ <item msgid="5220695614993094977">"MTP (protokol za transfer medija)"</item>
+ <item msgid="2086000968159047375">"PTP (protokol za prenos slika)"</item>
+ <item msgid="7398830860950841822">"RNDIS (USB eternet)"</item>
+ <item msgid="1718924214939774352">"Izvor zvuka"</item>
+ <item msgid="8126315616613006284">"MIDI"</item>
+ </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..54d2dfa
--- /dev/null
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+ <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nije moguće skenirati mreže"</string>
+ <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"Sačuvano"</string>
+ <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string>
+ <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfiguracija je otkazala"</string>
+ <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi veza je otkazala"</string>
+ <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem sa potvrdom autentičnosti"</string>
+ <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
+ <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven, automatsko povezivanje nije moguće."</string>
+ <string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_via_wfa" msgid="3805736726317410714">"Povezano preko Wi‑Fi pomoćnika"</string>
+ <string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
+ <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupna je preko pristupne tačke %1$s"</string>
+ <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Veza je uspostavljena, nema interneta"</string>
+ <string name="bluetooth_disconnected" msgid="6557104142667339895">"Veza je prekinuta"</string>
+ <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekidanje veze..."</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"Povezivanje…"</string>
+ <string name="bluetooth_connected" msgid="6038755206916626419">"Povezano"</string>
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"Uparivanje..."</string>
+ <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Povezano (bez telefona)"</string>
+ <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
+ <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano je (nema pristupa porukama)"</string>
+ <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez telefona ili medija)"</string>
+ <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medija"</string>
+ <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefona"</string>
+ <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos datoteke"</string>
+ <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ulazni uređaj"</string>
+ <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Pristup Internetu"</string>
+ <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deljenje kontakata"</string>
+ <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Koristite za deljenje kontakata"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deljenje internet veze"</string>
+ <string name="bluetooth_profile_map" msgid="5465271250454324383">"Pristup porukama"</string>
+ <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM kartici"</string>
+ <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano sa zvukom medija"</string>
+ <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano sa zvukom telefona"</string>
+ <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano sa serverom za prenos datoteka"</string>
+ <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezano je sa mapom"</string>
+ <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Veza sa tačkom pristupa uslugama je uspostavljena"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nije povezano sa serverom za prenos datoteka"</string>
+ <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezan sa ulaznim uređajem"</string>
+ <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povez. sa uređ. radi pristupa Internetu"</string>
+ <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokalna internet veza se deli sa uređajem"</string>
+ <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Koristi za pristup Internetu"</string>
+ <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Koristi se za mapu"</string>
+ <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Koristi za pristup SIM kartici"</string>
+ <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Korišćenje za zvuk medija"</string>
+ <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Korišćenje za audio telefona"</string>
+ <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Korišćenje za prenos datoteka"</string>
+ <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Koristi za ulaz"</string>
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string>
+ <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Otkaži"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje omogućava pristup kontaktima i istoriji poziva nakon povezivanja."</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Uparivanje sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Uparivanje sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguće zbog netačnog PIN-a ili pristupnog koda."</string>
+ <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nije moguće komunicirati sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> je odbio/la uparivanje"</string>
+ <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je isključen."</string>
+ <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi veza je prekinuta."</string>
+ <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi signal ima jednu crtu."</string>
+ <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi signal ima dve crte."</string>
+ <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi signal ima tri crte."</string>
+ <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi signal je najjači."</string>
+ <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+ <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string>
+ <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Internet povezivanje"</string>
+ <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosni hotspot"</string>
+ <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth privezivanje"</string>
+ <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Povezivanje sa internetom"</string>
+ <string name="tether_settings_title_all" msgid="8356136101061143841">"Povezivanje i prenosni hotspot"</string>
+ <string name="managed_user_title" msgid="8101244883654409696">"Profil za posao"</string>
+ <string name="user_guest" msgid="8475274842845401871">"Gost"</string>
+ <string name="unknown" msgid="1592123443519355854">"Nepoznato"</string>
+ <string name="running_process_item_user_label" msgid="3129887865552025943">"Korisnik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+ <string name="launch_defaults_some" msgid="313159469856372621">"Podešene su neke podrazumevane vrednosti"</string>
+ <string name="launch_defaults_none" msgid="4241129108140034876">"Nisu podešene podrazumevane vrednosti"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Podešavanja prelaska iz teksta u govor"</string>
+ <string name="tts_settings_title" msgid="1237820681016639683">"Izlaz za pretvaranje teksta u govor"</string>
+ <string name="tts_default_rate_title" msgid="6030550998379310088">"Brzina govora"</string>
+ <string name="tts_default_rate_summary" msgid="4061815292287182801">"Brzina izgovaranja teksta"</string>
+ <string name="tts_default_lang_title" msgid="8018087612299820556">"Jezik"</string>
+ <string name="tts_lang_use_system" msgid="2679252467416513208">"Koristi jezik sistema"</string>
+ <string name="tts_lang_not_selected" msgid="7395787019276734765">"Jezik nije izabran"</string>
+ <string name="tts_default_lang_summary" msgid="5219362163902707785">"Podešava glas specifičan za jezik namenjen govornom tekstu"</string>
+ <string name="tts_play_example_title" msgid="7094780383253097230">"Poslušaj primer"</string>
+ <string name="tts_play_example_summary" msgid="8029071615047894486">"Puštanje kratke demonstracije sinteze govora"</string>
+ <string name="tts_install_data_title" msgid="4264378440508149986">"Instaliraj glasovne podatke"</string>
+ <string name="tts_install_data_summary" msgid="5742135732511822589">"Instaliranje govornih podataka potrebnih za sintezu govora"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"Ova tehnologija za sintezu govora možda može da prikuplja sav tekst koji će biti izgovoren, uključujući lične podatke kao što su lozinke i brojevi kreditnih kartica. To potiče iz tehnologije <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Želite li da omogućite korišćenje ove tehnologije za sintezu govora?"</string>
+ <string name="tts_engine_network_required" msgid="1190837151485314743">"Za ovaj jezik je potrebna ispravna mrežna veza za pretvaranje teksta u govor."</string>
+ <string name="tts_default_sample_string" msgid="4040835213373086322">"Ovo je primer sinteze govora"</string>
+ <string name="tts_status_title" msgid="7268566550242584413">"Status podrazumevanog jezika"</string>
+ <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> je podržan u potpunosti"</string>
+ <string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> zahteva vezu sa mrežom"</string>
+ <string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> nije podržan"</string>
+ <string name="tts_status_checking" msgid="5339150797940483592">"Proverava se..."</string>
+ <string name="tts_engine_settings_title" msgid="3499112142425680334">"Podešavanja za <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
+ <string name="tts_engine_settings_button" msgid="1030512042040722285">"Pokreni podešavanja mašine"</string>
+ <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Željena mašina"</string>
+ <string name="tts_general_section_title" msgid="4402572014604490502">"Opšte"</string>
+ <string-array name="tts_rate_entries">
+ <item msgid="6695494874362656215">"Veoma sporo"</item>
+ <item msgid="4795095314303559268">"Sporo"</item>
+ <item msgid="8903157781070679765">"Normalno"</item>
+ <item msgid="164347302621392996">"Brzo"</item>
+ <item msgid="5794028588101562009">"Brže"</item>
+ <item msgid="7163942783888652942">"Veoma brzo"</item>
+ <item msgid="7831712693748700507">"Ubrzano"</item>
+ <item msgid="5194774745031751806">"Veoma ubrzano"</item>
+ <item msgid="9085102246155045744">"Najbrže"</item>
+ </string-array>
+ <string name="choose_profile" msgid="8229363046053568878">"Izaberite profil"</string>
+ <string name="category_personal" msgid="1299663247844969448">"Lično"</string>
+ <string name="category_work" msgid="8699184680584175622">"Posao"</string>
+ <string name="development_settings_title" msgid="215179176067683667">"Opcije za programera"</string>
+ <string name="development_settings_enable" msgid="542530994778109538">"Omogući opcije za programera"</string>
+ <string name="development_settings_summary" msgid="1815795401632854041">"Podešavanje opcija za programiranje aplikacije"</string>
+ <string name="development_settings_not_available" msgid="4308569041701535607">"Opcije za programere nisu dostupne za ovog korisnika"</string>
+ <string name="vpn_settings_not_available" msgid="956841430176985598">"Podešavanja VPN-a nisu dostupna za ovog korisnika"</string>
+ <string name="tethering_settings_not_available" msgid="6765770438438291012">"Podešavanja privezivanja nisu dostupna za ovog korisnika"</string>
+ <string name="apn_settings_not_available" msgid="7873729032165324000">"Podešavanja naziva pristupne tačke nisu dostupna za ovog korisnika"</string>
+ <string name="enable_adb" msgid="7982306934419797485">"Otklanjanje USB grešaka"</string>
+ <string name="enable_adb_summary" msgid="4881186971746056635">"Režim otklanjanja grešaka kada je USB povezan"</string>
+ <string name="clear_adb_keys" msgid="4038889221503122743">"Opozivanje odobrenja za uklanjanje USB grešaka"</string>
+ <string name="bugreport_in_power" msgid="7923901846375587241">"Prečica za izveštaj o greškama"</string>
+ <string name="bugreport_in_power_summary" msgid="1778455732762984579">"Prikaži dugme u meniju napajanja za pravljenje izveštaja o greškama"</string>
+ <string name="keep_screen_on" msgid="1146389631208760344">"Ne zaključavaj"</string>
+ <string name="keep_screen_on_summary" msgid="2173114350754293009">"Ekran neće biti u režimu spavanja tokom punjenja"</string>
+ <string name="bt_hci_snoop_log" msgid="3340699311158865670">"Omogući snoop evidenciju za Bluetooth HCI"</string>
+ <string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"Snimi sve Bluetooth HCI pakete u datoteci"</string>
+ <string name="oem_unlock_enable" msgid="6040763321967327691">"Otključavanje OEM-a"</string>
+ <string name="oem_unlock_enable_summary" msgid="4720281828891618376">"Dozvoli otključavanje funkcije za pokretanje"</string>
+ <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"Želite li da dozvolite otključavanje proizvođača originalne opreme (OEM)?"</string>
+ <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"UPOZORENJE: Funkcije za zaštitu uređaja neće funkcionisati na ovom uređaju dok je ovo podešavanje uključeno."</string>
+ <string name="mock_location_app" msgid="7966220972812881854">"Izaberi aplikaciju za lažnu lokaciju"</string>
+ <string name="mock_location_app_not_set" msgid="809543285495344223">"Aplikacija za lažnu lokaciju nije podešena"</string>
+ <string name="mock_location_app_set" msgid="8966420655295102685">"Aplikacija za lažnu lokaciju: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_networking_category" msgid="7044075693643009662">"Umrežavanje"</string>
+ <string name="wifi_display_certification" msgid="8611569543791307533">"Sertifikacija bežičnog ekrana"</string>
+ <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljniju evidenciju za Wi‑Fi"</string>
+ <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agresivan prelaz sa Wi‑Fi mreže na mobilnu"</string>
+ <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string>
+ <string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
+ <string name="mobile_data_always_on" msgid="7745605759775320362">"Podaci za mobilne uređaje su uvek aktivni"</string>
+ <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
+ <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Povećava nivo evidentiranja za Wi‑Fi. Prikaz po SSID RSSI-u u biraču Wi‑Fi mreže"</string>
+ <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Kada se omogući, Wi‑Fi će biti agresivniji pri prebacivanju mreže za prenos podataka na Mobilnu, kada je Wi‑Fi signal slab"</string>
+ <string name="wifi_allow_scan_with_traffic_summary" msgid="2575101424972686310">"Dozvoli/zabrani skeniranje Wi-Fi-ja u romingu na osnovu prisutnog protoka podataka na interfejsu"</string>
+ <string name="select_logd_size_title" msgid="7433137108348553508">"Veličine bafera podataka u programu za evidentiranje"</string>
+ <string name="select_logd_size_dialog_title" msgid="1206769310236476760">"Izaberite veličine po baferu evidencije"</string>
+ <string name="select_usb_configuration_title" msgid="2649938511506971843">"Izaberite konfiguraciju USB-a"</string>
+ <string name="select_usb_configuration_dialog_title" msgid="6385564442851599963">"Izaberite konfiguraciju USB-a"</string>
+ <string name="allow_mock_location" msgid="2787962564578664888">"Dozvoli lažne lokacije"</string>
+ <string name="allow_mock_location_summary" msgid="317615105156345626">"Dozvoli lažne lokacije"</string>
+ <string name="debug_view_attributes" msgid="6485448367803310384">"Omogući proveru atributa za pregled"</string>
+ <string name="legacy_dhcp_client_summary" msgid="163383566317652040">"Koristite DHCP klijent iz Lollipop-a umesto novog Android DHCP klijenta."</string>
+ <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Neka podaci za mobilne uređaje uvek budu aktivni, čak i kada je Wi‑Fi aktivan (radi brze promene mreže)."</string>
+ <string name="adb_warning_title" msgid="6234463310896563253">"Dozvoli otklanjanje USB grešaka?"</string>
+ <string name="adb_warning_message" msgid="7316799925425402244">"Otklanjanje USB grešaka namenjeno je samo za svrhe programiranja. Koristite ga za kopiranje podataka sa računara na uređaj i obrnuto, instaliranje aplikacija na uređaju bez obaveštenja i čitanje podataka iz evidencije."</string>
+ <string name="adb_keys_warning_message" msgid="5659849457135841625">"Želite li da opozovete pristup otklanjanju USB grešaka sa svih računara koje ste prethodno odobrili?"</string>
+ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Želite li da omogućite programerska podešavanja?"</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Ova podešavanja su namenjena samo za programiranje. Mogu da izazovu prestanak funkcionisanja ili neočekivano ponašanje uređaja i aplikacija na njemu."</string>
+ <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije preko USB-a"</string>
+ <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Proverava da li su aplikacije instalirane preko ADB-a/ADT-a štetne."</string>
+ <string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
+ <string name="enable_terminal_summary" msgid="67667852659359206">"Omogući aplik. terminala za pristup lokalnom komandnom okruženju"</string>
+ <string name="hdcp_checking_title" msgid="8605478913544273282">"HDCP provera"</string>
+ <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"Podešavanje ponašanja HDCP provere"</string>
+ <string name="debug_debugging_category" msgid="6781250159513471316">"Otklanjanje grešaka"</string>
+ <string name="debug_app" msgid="8349591734751384446">"Izaberite aplikaciju za otklanjanje grešaka"</string>
+ <string name="debug_app_not_set" msgid="718752499586403499">"Nema podešenih aplikacija za otklanjanje grešaka"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"Aplikacija za otklanjanje grešaka: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="select_application" msgid="5156029161289091703">"Biranje aplikacije"</string>
+ <string name="no_application" msgid="2813387563129153880">"Nijedna"</string>
+ <string name="wait_for_debugger" msgid="1202370874528893091">"Sačekaj program za otklanjanje grešaka"</string>
+ <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Aplikacija čeka program za otklanjanje grešaka da priloži pre izvršavanja"</string>
+ <string name="debug_input_category" msgid="1811069939601180246">"Unos"</string>
+ <string name="debug_drawing_category" msgid="6755716469267367852">"Crtanje"</string>
+ <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Hardverski ubrzano prikazivanje"</string>
+ <string name="media_category" msgid="4388305075496848353">"Mediji"</string>
+ <string name="debug_monitoring_category" msgid="7640508148375798343">"Nadgledanje"</string>
+ <string name="strict_mode" msgid="1938795874357830695">"Omogućen je strogi režim"</string>
+ <string name="strict_mode_summary" msgid="142834318897332338">"Neka ekran treperi kada aplikacije obavljaju duge operacije na glavnoj niti"</string>
+ <string name="pointer_location" msgid="6084434787496938001">"Lokacija pokazivača"</string>
+ <string name="pointer_location_summary" msgid="840819275172753713">"Postav. element sa trenutnim podacima o dodiru"</string>
+ <string name="show_touches" msgid="1356420386500834339">"Prikaži dodire"</string>
+ <string name="show_touches_summary" msgid="6684407913145150041">"Prikaži vizuelne povratne informacije za dodire"</string>
+ <string name="show_screen_updates" msgid="5470814345876056420">"Prikaži ažuriranja površine"</string>
+ <string name="show_screen_updates_summary" msgid="2569622766672785529">"Osvetli sve površine prozora kada se ažuriraju"</string>
+ <string name="show_hw_screen_updates" msgid="5036904558145941590">"Prikaži ažur. GPU prikaza"</string>
+ <string name="show_hw_screen_updates_summary" msgid="1115593565980196197">"Osvetli prikaze u prozor. kada se crta sa GPU-om"</string>
+ <string name="show_hw_layers_updates" msgid="5645728765605699821">"Prikaži ažuriranja hardverskih slojeva"</string>
+ <string name="show_hw_layers_updates_summary" msgid="5296917233236661465">"Hardverski slojevi trepere zeleno kada se ažuriraju"</string>
+ <string name="debug_hw_overdraw" msgid="2968692419951565417">"Otkloni greške GPU preklapanja"</string>
+ <string name="disable_overlays" msgid="2074488440505934665">"Onemog. HW post. elemente"</string>
+ <string name="disable_overlays_summary" msgid="3578941133710758592">"Uvek koristi GPU za komponovanje ekrana"</string>
+ <string name="simulate_color_space" msgid="6745847141353345872">"Simuliraj prostor boje"</string>
+ <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Omogući OpenGL tragove"</string>
+ <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Onemogući USB preusm. zvuka"</string>
+ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Onemogući automat. preusmer. na USB audio periferne uređaje"</string>
+ <string name="debug_layout" msgid="5981361776594526155">"Prikaži granice rasporeda"</string>
+ <string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice klipa, margine itd."</string>
+ <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni smer rasporeda zdesna nalevo"</string>
+ <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smer rasporeda ekrana zdesna nalevo za sve lokalitete"</string>
+ <string name="show_cpu_usage" msgid="2389212910758076024">"Prik. upotrebu procesora"</string>
+ <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Postav. element sa trenutnom upotrebom procesora"</string>
+ <string name="force_hw_ui" msgid="6426383462520888732">"Prinudni prikaz pom. GPU"</string>
+ <string name="force_hw_ui_summary" msgid="5535991166074861515">"Prinudno koristi GPU za 2D crtanje"</string>
+ <string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
+ <string name="force_msaa_summary" msgid="9123553203895817537">"Omogući 4x MSAA u OpenGL ES 2.0 aplikacijama"</string>
+ <string name="show_non_rect_clip" msgid="505954950474595172">"Otkloni greške u vezi sa radnjama za isecanje oblasti koje nisu pravougaonog oblika"</string>
+ <string name="track_frame_time" msgid="6146354853663863443">"Prikaži profil pomoću GPU"</string>
+ <string name="window_animation_scale_title" msgid="6162587588166114700">"Razmera animacije prozora"</string>
+ <string name="transition_animation_scale_title" msgid="387527540523595875">"Razmera animacije prelaza"</string>
+ <string name="animator_duration_scale_title" msgid="3406722410819934083">"Animatorova razmera trajanja"</string>
+ <string name="overlay_display_devices_title" msgid="5364176287998398539">"Simuliraj sekundarne ekrane"</string>
+ <string name="debug_applications_category" msgid="4206913653849771549">"Aplikacije"</string>
+ <string name="immediately_destroy_activities" msgid="1579659389568133959">"Ne čuvaj aktivnosti"</string>
+ <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Uništi svaku aktivnost čim je korisnik napusti"</string>
+ <string name="app_process_limit_title" msgid="4280600650253107163">"Ograničenje pozadinskih procesa"</string>
+ <string name="show_all_anrs" msgid="28462979638729082">"Prikaži sve ANR-ove"</string>
+ <string name="show_all_anrs_summary" msgid="641908614413544127">"Prikaži dijalog Aplikacija ne reaguje za aplikacije u pozadini"</string>
+ <string name="force_allow_on_external" msgid="3215759785081916381">"Prinudno dozvoli aplikacije u spoljnoj"</string>
+ <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
+ <string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
+ <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
+ <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
+ <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
+ <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
+ <string name="local_backup_password_toast_success" msgid="582016086228434290">"Postavljena je nova lozinka rezervne kopije"</string>
+ <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"Nova lozinka i njena potvrda se ne podudaraju"</string>
+ <string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"Postavljanje lozinke rezervne kopije nije uspelo"</string>
+ <string-array name="color_mode_names">
+ <item msgid="2425514299220523812">"Živopisan (podrazumevano)"</item>
+ <item msgid="8446070607501413455">"Prirodan"</item>
+ <item msgid="6553408765810699025">"Standardan"</item>
+ </string-array>
+ <string-array name="color_mode_descriptions">
+ <item msgid="4979629397075120893">"Poboljšane boje"</item>
+ <item msgid="8280754435979370728">"Prirodne boje nalik onima koje registruje oko"</item>
+ <item msgid="5363960654009010371">"Boje optimizovane za digitalni sadržaj"</item>
+ </string-array>
+ <string name="inactive_apps_title" msgid="1317817863508274533">"Neaktivne aplikacije"</string>
+ <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"Neaktivna. Dodirnite da biste je aktivirali."</string>
+ <string name="inactive_app_active_summary" msgid="4512911571954375968">"Aktivna. Dodirnite da biste je deaktivirali."</string>
+ <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
+ <string name="runningservices_settings_summary" msgid="854608995821032748">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
+ <string name="night_mode_title" msgid="2594133148531256513">"Noćni režim"</string>
+ <string name="night_mode_summary" msgid="9196605054622017193">"%s"</string>
+ <string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
+ <string name="night_mode_yes" msgid="2218157265997633432">"Uvek uključeno"</string>
+ <string name="night_mode_auto" msgid="7508348175804304327">"Automatski"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
+ <string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
+ <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
+ <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
+ <string name="title_convert_fbe" msgid="1263622876196444453">"Konvertovanje u šifrovanje pojedinačnih datoteka"</string>
+ <string name="convert_to_fbe_warning" msgid="6139067817148865527">"Konvertujte šifrovanje particije podataka u šifrovanje pojedinačnih datoteka.\n !!Upozorenje!! Time brišete sve podatke.\n Ovo je alfa verzija funkcije i verovatno neće funkcionisati ispravno.\n Pritisnite „Izbriši i konvertuj...“ da biste nastavili."</string>
+ <string name="button_convert_fbe" msgid="5152671181309826405">"Izbriši i konvertuj..."</string>
+ <string name="picture_color_mode" msgid="4560755008730283695">"Režim boja slika"</string>
+ <string name="picture_color_mode_desc" msgid="1141891467675548590">"Koristi sRGB"</string>
+ <string name="daltonizer_mode_disabled" msgid="7482661936053801862">"Onemogućeno je"</string>
+ <string name="daltonizer_mode_monochromacy" msgid="8485709880666106721">"Jednobojnost"</string>
+ <string name="daltonizer_mode_deuteranomaly" msgid="5475532989673586329">"Deuteranomalija (crveno-zeleno)"</string>
+ <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Protanomalija (crveno-zeleno)"</string>
+ <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"Tritanomalija (plavo-žuto)"</string>
+ <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Korekcija boja"</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Ova funkcija je eksperimentalna i može da utiče na performanse."</string>
+ <string name="daltonizer_type_overridden" msgid="3116947244410245916">"Zamenjuje ga <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 277800d..42339ef 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Винаги да се използва проверка с HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Изключено"</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Изключено"</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Рег. буфер – 64 КБ"</item>
- <item msgid="2822309747675758628">"Рег. буфер – 256 КБ"</item>
- <item msgid="6699306198357496731">"Рег. буфер – 1 МБ"</item>
- <item msgid="5748528643937500349">"Рег. буфер – 4 МБ"</item>
- <item msgid="1978629051085111592">"Рег. буфер – 16 МБ"</item>
+ <item msgid="6921048829791179331">"Изключено"</item>
+ <item msgid="2969458029344750262">"Рег. буфер – 64 КБ"</item>
+ <item msgid="1342285115665698168">"Рег. буфер – 256 КБ"</item>
+ <item msgid="1314234299552254621">"Рег. буфер – 1 МБ"</item>
+ <item msgid="3606047780792894151">"Рег. буфер – 4 МБ"</item>
+ <item msgid="5431354956856655120">"Рег. буфер – 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацията е изключена"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 105e533..95badc5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Деактивирано"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Винаги включено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Внедряване на WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Задаване на внедряването на WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Преобразуване към шифроване на ниво файл"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Преобразуване…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Данните вече са шифровани на ниво файл"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/arrays.xml b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
index 7729a4d..b863934 100644
--- a/packages/SettingsLib/res/values-bn-rBD/arrays.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"সর্বদা HDCP পরীক্ষণ ব্যবহার করুন"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"৬৪০০০"</item>
- <item msgid="505611754508988476">"২৫৬০০০"</item>
- <item msgid="6361286924268716397">"১০০০০০০"</item>
- <item msgid="6405203239560695266">"৪০০০০০০"</item>
- <item msgid="3025431211013424097">"১৬০০০০০০"</item>
+ <item msgid="8665206199209698501">"বন্ধ আছে"</item>
+ <item msgid="1593289376502312923">"৬৪K"</item>
+ <item msgid="487545340236145324">"২৫৬K"</item>
+ <item msgid="2423528675294333831">"১M"</item>
+ <item msgid="180883774509476541">"৪M"</item>
+ <item msgid="2803199102589126938">"১৬M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"৬৪০০০"</item>
- <item msgid="3534782711045262344">"২৫৬০০০"</item>
- <item msgid="8085867209202153403">"১০০০০০০"</item>
+ <item msgid="6089470720451068364">"বন্ধ আছে"</item>
+ <item msgid="4622460333038586791">"৬৪K"</item>
+ <item msgid="2212125625169582330">"২৫৬K"</item>
+ <item msgid="1704946766699242653">"১M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"লগ বাফার প্রতি 64K"</item>
- <item msgid="2822309747675758628">"লগ বাফার প্রতি 256K"</item>
- <item msgid="6699306198357496731">"লগ বাফার প্রতি 1M"</item>
- <item msgid="5748528643937500349">"লগ বাফার প্রতি 4M"</item>
- <item msgid="1978629051085111592">"লগ বাফার প্রতি 16M"</item>
+ <item msgid="6921048829791179331">"বন্ধ আছে"</item>
+ <item msgid="2969458029344750262">"লগ বাফার প্রতি ৬৪K"</item>
+ <item msgid="1342285115665698168">"লগ বাফার প্রতি ২৫৬K"</item>
+ <item msgid="1314234299552254621">"লগ বাফার প্রতি ১M"</item>
+ <item msgid="3606047780792894151">"লগ বাফার প্রতি ৪M"</item>
+ <item msgid="5431354956856655120">"লগ বাফার প্রতি ১৬M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"অ্যানিমেশন বন্ধ করুন"</item>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 5c83183..e4d97d7 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ডেস্কটপ পুরো ব্যাকআপের জন্য পাসওয়ার্ড পরিবর্তন বা মুছে ফেলার জন্য স্পর্শ করুন"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"অক্ষম করা রয়েছে"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"সবসময় চালু"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"স্বয়ংক্রিয়"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"ওয়েবভিউ প্রয়োগ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ওয়েবভিউ প্রয়োগ সেট করুন"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ফাইল এনক্রিপশান রূপান্তর করুন"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"রূপান্তর করুন..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ফাইল ইতিমধ্যেই এনক্রিপ্ট করা রয়েছে"</string>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
index ab80ccc..99c8a27e 100644
--- a/packages/SettingsLib/res/values-ca/arrays.xml
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilitza sempre la comprovació HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"No"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1.000.000"</item>
+ <item msgid="6089470720451068364">"No"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/memòria intermèdia reg."</item>
- <item msgid="2822309747675758628">"256 K/memòria intermèdia reg."</item>
- <item msgid="6699306198357496731">"1 M/memòria intermèdia reg."</item>
- <item msgid="5748528643937500349">"4 M/memòria intermèdia reg."</item>
- <item msgid="1978629051085111592">"16 M/memòria intermèdia reg."</item>
+ <item msgid="6921048829791179331">"No"</item>
+ <item msgid="2969458029344750262">"64 K / memòria intermèdia reg."</item>
+ <item msgid="1342285115665698168">"256 K / memòria intermèdia reg."</item>
+ <item msgid="1314234299552254621">"1 M / memòria intermèdia reg."</item>
+ <item msgid="3606047780792894151">"4 M / memòria intermèdia reg."</item>
+ <item msgid="5431354956856655120">"16 M / memòria intermèdia reg."</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animació desactivada"</item>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 71a331d2..93b6438 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca per canviar o eliminar la contrasenya per a còpies de seguretat d\'ordinador completes"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desactivat"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre activat"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automàtic"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementació de WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configura la implementació de WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteix en l\'encriptació de fitxers"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteix…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"El fitxer ja està encriptat"</string>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
index d46781a..8953485 100644
--- a/packages/SettingsLib/res/values-cs/arrays.xml
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vždy používat kontrolu HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Vypnuto"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Vypnuto"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB na vyrovnávací paměť protokolů"</item>
- <item msgid="2822309747675758628">"256 kB na vyrovnávací paměť protokolů"</item>
- <item msgid="6699306198357496731">"1 MB na vyrovnávací paměť protokolů"</item>
- <item msgid="5748528643937500349">"4 MB na vyrovnávací paměť protokolů"</item>
- <item msgid="1978629051085111592">"16 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="6921048829791179331">"Vypnuto"</item>
+ <item msgid="2969458029344750262">"64 kB na vyrovnávací paměť protokolů"</item>
+ <item msgid="1342285115665698168">"256 kB na vyrovnávací paměť protokolů"</item>
+ <item msgid="1314234299552254621">"1 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="3606047780792894151">"4 MB na vyrovnávací paměť protokolů"</item>
+ <item msgid="5431354956856655120">"16 MB na vyrovnávací paměť protokolů"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animace je vypnuta"</item>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 8ec5e25..beb8f94 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Velikost všech aktivit bude možné změnit na několik oken (bez ohledu na hodnoty manifestu)."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy v počítači"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Vypnuto"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuto"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementace WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavte implementaci WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Převést na šifrování souborů"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Převést…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Obsah je již na úrovni souborů zašifrován"</string>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
index 2935489..d700c05 100644
--- a/packages/SettingsLib/res/values-da/arrays.xml
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Brug altid HDCP-kontrol"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Fra"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Fra"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB pr. logbuffer"</item>
- <item msgid="2822309747675758628">"256 KB pr. logbuffer"</item>
- <item msgid="6699306198357496731">"1 MB pr. logbuffer"</item>
- <item msgid="5748528643937500349">"4 MB pr. logbuffer"</item>
- <item msgid="1978629051085111592">"16 MB pr. logbuffer"</item>
+ <item msgid="6921048829791179331">"Fra"</item>
+ <item msgid="2969458029344750262">"64 kB pr. logbuffer"</item>
+ <item msgid="1342285115665698168">"256 kB pr. logbuffer"</item>
+ <item msgid="1314234299552254621">"1 MB pr. logbuffer"</item>
+ <item msgid="3606047780792894151">"4 MB pr. logbuffer"</item>
+ <item msgid="5431354956856655120">"16 MB pr. logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation fra"</item>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 747bd14..3923dbd 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Sørger for, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Deaktiveret"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altid slået til"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Konfigurer WebView-implementering"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til filkryptering"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede filkrypteret"</string>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
index d2a7f0d..a9c802d 100644
--- a/packages/SettingsLib/res/values-de/arrays.xml
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP-Prüfung immer verwenden"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64.000"</item>
- <item msgid="505611754508988476">"256.000"</item>
- <item msgid="6361286924268716397">"1 Mio."</item>
- <item msgid="6405203239560695266">"4 Mio."</item>
- <item msgid="3025431211013424097">"16 Mio."</item>
+ <item msgid="8665206199209698501">"Aus"</item>
+ <item msgid="1593289376502312923">"64.000"</item>
+ <item msgid="487545340236145324">"256.000"</item>
+ <item msgid="2423528675294333831">"1 Mio."</item>
+ <item msgid="180883774509476541">"4 Mio."</item>
+ <item msgid="2803199102589126938">"16 Mio."</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1 Mio."</item>
+ <item msgid="6089470720451068364">"Aus"</item>
+ <item msgid="4622460333038586791">"64.000"</item>
+ <item msgid="2212125625169582330">"256.000"</item>
+ <item msgid="1704946766699242653">"1 Mio."</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64.000 pro Puffer"</item>
- <item msgid="2822309747675758628">"256.000 pro Puffer"</item>
- <item msgid="6699306198357496731">"1 Mio. pro Puffer"</item>
- <item msgid="5748528643937500349">"4 Mio. pro Puffer"</item>
- <item msgid="1978629051085111592">"16 Mio. pro Puffer"</item>
+ <item msgid="6921048829791179331">"Aus"</item>
+ <item msgid="2969458029344750262">"64.000 pro Puffer"</item>
+ <item msgid="1342285115665698168">"256.000 pro Puffer"</item>
+ <item msgid="1314234299552254621">"1 Mio. pro Puffer"</item>
+ <item msgid="3606047780792894151">"4 Mio. pro Puffer"</item>
+ <item msgid="5431354956856655120">"16 Mio. pro Puffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation aus"</item>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 9b60b20..0b1238b 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen berühren"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Deaktiviert"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Immer an"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-Implementierung"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-Implementierung festlegen"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Zu Dateiverschlüsselung wechseln"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Wechseln…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dateiverschlüsselung wird bereits verwendet."</string>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
index 2672eec..91f9d6a 100644
--- a/packages/SettingsLib/res/values-el/arrays.xml
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Να χρησιμοποιείται πάντα έλεγχος HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Ανενεργό"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Ανενεργό"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="2822309747675758628">"256 K ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="6699306198357496731">"1 Μ ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="5748528643937500349">"4 M ανά μεγ.πρ.μν.καταγρ."</item>
- <item msgid="1978629051085111592">"16 M ανά μεγ.πρ.μν.καταγρ."</item>
+ <item msgid="6921048829791179331">"Ανενεργό"</item>
+ <item msgid="2969458029344750262">"64 K ανά πρ. μν. αρχ. καταγρ."</item>
+ <item msgid="1342285115665698168">"256 K ανά πρ. μν. αρχ. καταγρ."</item>
+ <item msgid="1314234299552254621">"1 Μ ανά προσ. μν. αρχ. καταγρ."</item>
+ <item msgid="3606047780792894151">"4 M ανά προσ. μν. αρχ. καταγρ."</item>
+ <item msgid="5431354956856655120">"16 M ανά πρ. μν. αρχ. καταγρ."</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Κινούμ.εικόνες απενεργοποιημένες"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 008491f..c3acca7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Εφ/κός κωδικός desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Αγγίξτε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Ανενεργό"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Πάντα ενεργό"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Αυτόματο"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Υλοποίηση WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ορισμός υλοποίησης WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Μετατροπή σε κρυπτογράφηση αρχείου"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Μετατροπή…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Με κρυπτογράφηση αρχείου"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index dabc72ef..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index dabc72ef..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 21340d8..05518900 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Always use HDCP checking"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Off"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Off"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K per log buffer"</item>
- <item msgid="2822309747675758628">"256 K per log buffer"</item>
- <item msgid="6699306198357496731">"1 M per log buffer"</item>
- <item msgid="5748528643937500349">"4 M per log buffer"</item>
- <item msgid="1978629051085111592">"16 M per log buffer"</item>
+ <item msgid="6921048829791179331">"Off"</item>
+ <item msgid="2969458029344750262">"64 K per log buffer"</item>
+ <item msgid="1342285115665698168">"256 K per log buffer"</item>
+ <item msgid="1314234299552254621">"1 M per log buffer"</item>
+ <item msgid="3606047780792894151">"4 M per log buffer"</item>
+ <item msgid="5431354956856655120">"16 M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation off"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index dabc72ef..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disabled"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Always on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatic"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convert to file encryption"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convert…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Already file encrypted"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
index 52992d55..1b7a9f0 100644
--- a/packages/SettingsLib/res/values-es-rUS/arrays.xml
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Siempre utilizar comprobación HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desactivado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desactivado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/búfer registro"</item>
- <item msgid="2822309747675758628">"256 K/búfer registro"</item>
- <item msgid="6699306198357496731">"1 M/búfer registro"</item>
- <item msgid="5748528643937500349">"4 M/búfer registro"</item>
- <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+ <item msgid="6921048829791179331">"Desactivado"</item>
+ <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+ <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+ <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+ <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+ <item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 2612943..855b72c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar o eliminar la contraseña de las copias de seguridad completas de tu escritorio."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar la implementación de WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a encriptación de archivo"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está encriptado"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 0493217..e4b661e 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar siempre comprobación de HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"No"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"No"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/búfer registro"</item>
- <item msgid="2822309747675758628">"256 K/búfer registro"</item>
- <item msgid="6699306198357496731">"1 M/búfer registro"</item>
- <item msgid="5748528643937500349">"4 M/búfer registro"</item>
- <item msgid="1978629051085111592">"16 M/búfer registro"</item>
+ <item msgid="6921048829791179331">"No"</item>
+ <item msgid="2969458029344750262">"64 K/búfer registro"</item>
+ <item msgid="1342285115665698168">"256 K/búfer registro"</item>
+ <item msgid="1314234299552254621">"1 M/búfer registro"</item>
+ <item msgid="3606047780792894151">"4 M/búfer registro"</item>
+ <item msgid="5431354956856655120">"16 M/búfer registro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 02a8306..858c1b6 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocar para cambiar o quitar la contraseña para las copias de seguridad completas de ordenador"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inhabilitado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Siempre activado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a cifrado de archivo"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está cifrado"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/arrays.xml b/packages/SettingsLib/res/values-et-rEE/arrays.xml
index 5bf13bb..9731983 100644
--- a/packages/SettingsLib/res/values-et-rEE/arrays.xml
+++ b/packages/SettingsLib/res/values-et-rEE/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Kasuta alati HDCP-kontrollimist"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 000"</item>
- <item msgid="505611754508988476">"256 000"</item>
- <item msgid="6361286924268716397">"1 000 000"</item>
- <item msgid="6405203239560695266">"4 000 000"</item>
- <item msgid="3025431211013424097">"16 000 000"</item>
+ <item msgid="8665206199209698501">"Väljas"</item>
+ <item msgid="1593289376502312923">"64 000"</item>
+ <item msgid="487545340236145324">"256 000"</item>
+ <item msgid="2423528675294333831">"1 000 000"</item>
+ <item msgid="180883774509476541">"4 000 000"</item>
+ <item msgid="2803199102589126938">"16 000 000"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 000"</item>
- <item msgid="3534782711045262344">"256 000"</item>
- <item msgid="8085867209202153403">"1 000 000"</item>
+ <item msgid="6089470720451068364">"Väljas"</item>
+ <item msgid="4622460333038586791">"64 000"</item>
+ <item msgid="2212125625169582330">"256 000"</item>
+ <item msgid="1704946766699242653">"1 000 000"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 k / logipuhver"</item>
- <item msgid="2822309747675758628">"256 k / logipuhver"</item>
- <item msgid="6699306198357496731">"1 mln / logipuhver"</item>
- <item msgid="5748528643937500349">"4 mln / logipuhver"</item>
- <item msgid="1978629051085111592">"16 mln / logipuhver"</item>
+ <item msgid="6921048829791179331">"Väljas"</item>
+ <item msgid="2969458029344750262">"64 000 / logipuhver"</item>
+ <item msgid="1342285115665698168">"256 000 / logipuhver"</item>
+ <item msgid="1314234299552254621">"1 000 000 / logipuhver"</item>
+ <item msgid="3606047780792894151">"4 000 000 / logipuhver"</item>
+ <item msgid="5431354956856655120">"16 000 000 / logipuhver"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsioon väljas"</item>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 5fb55eb..7f1056c 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Muudab kõigi tegevuste suurused mitme aknaga vaates olenemata manifesti väärtustest muudetavaks."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Lubatakse katseliste vabas vormis akende tugi."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Arvutivarunduse parool"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Täielikud arvutivarundused pole praegu kaitstud"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Puudutage, et muuta või eemaldada täielike arvutivarunduste parool"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Keelatud"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alati sees"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automaatne"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView\' rakendamine"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView\' rakendamise seadistamine"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Teisendamine failikrüpteeringuga andmeteks"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Teisenda …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Juba failikrüpteeringuga"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/arrays.xml b/packages/SettingsLib/res/values-eu-rES/arrays.xml
index 707ace5..b72b537 100644
--- a/packages/SettingsLib/res/values-eu-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-eu-rES/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Erabili beti HDCP egiaztapena"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desaktibatuta"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desaktibatuta"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K erregistroen bufferreko"</item>
- <item msgid="2822309747675758628">"256 K erregistroen bufferreko"</item>
- <item msgid="6699306198357496731">"1 M erregistroen bufferreko"</item>
- <item msgid="5748528643937500349">"4 M erregistroen bufferreko"</item>
- <item msgid="1978629051085111592">"16 M erregistroen bufferreko"</item>
+ <item msgid="6921048829791179331">"Desaktibatuta"</item>
+ <item msgid="2969458029344750262">"64 K erregistroen bufferreko"</item>
+ <item msgid="1342285115665698168">"256 K erregistroen bufferreko"</item>
+ <item msgid="1314234299552254621">"1 M erregistroen bufferreko"</item>
+ <item msgid="3606047780792894151">"4 M erregistroen bufferreko"</item>
+ <item msgid="5431354956856655120">"16 M erregistroen bufferreko"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazioa desaktibatuta"</item>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 9f62710..fe5fc29 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ukitu ordenagailuko babeskopia osoak egiteko pasahitza aldatzeko edo kentzeko"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desgaituta"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Beti aktibatuta"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatikoa"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView implementation"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Set WebView implementation"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Eman fitxategietan oinarritutako enkriptatzea"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Enkriptatu…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fitxategietan oinarritutako enkriptatzea dauka dagoeneko"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index d75280b..1b4e335 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"همیشه از بررسی HDCP استفاده شود"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"۶۴ کیلوبایت"</item>
- <item msgid="505611754508988476">"۲۵۶ کیلوبایت"</item>
- <item msgid="6361286924268716397">"۱ مگابایت"</item>
- <item msgid="6405203239560695266">"۴ مگابایت"</item>
- <item msgid="3025431211013424097">"۱۶ مگابایت"</item>
+ <item msgid="8665206199209698501">"خاموش"</item>
+ <item msgid="1593289376502312923">"۶۴ هزار"</item>
+ <item msgid="487545340236145324">"۲۵۶ هزار"</item>
+ <item msgid="2423528675294333831">"۱ میلیون"</item>
+ <item msgid="180883774509476541">"۴ میلیون"</item>
+ <item msgid="2803199102589126938">"۱۶ میلیون"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"۶۴ کیلوبایت"</item>
- <item msgid="3534782711045262344">"۲۵۶ کیلوبایت"</item>
- <item msgid="8085867209202153403">"۱ مگابایت"</item>
+ <item msgid="6089470720451068364">"خاموش"</item>
+ <item msgid="4622460333038586791">"۶۴ هزار"</item>
+ <item msgid="2212125625169582330">"۲۵۶ هزار"</item>
+ <item msgid="1704946766699242653">"۱ میلیون"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"۶۴K در حافظه موقت ثبت"</item>
- <item msgid="2822309747675758628">"۲۵۶Kدر حافظه موقت ثبت"</item>
- <item msgid="6699306198357496731">"۱Mدر حافظه موقت ثبت"</item>
- <item msgid="5748528643937500349">"۴M در حافظه موقت ثبت"</item>
- <item msgid="1978629051085111592">"۱۶M در حافظه موقت ثبت"</item>
+ <item msgid="6921048829791179331">"خاموش"</item>
+ <item msgid="2969458029344750262">"۶۴ هزار در هر بافر گزارش"</item>
+ <item msgid="1342285115665698168">"۲۵۶ هزار در هر بافر گزارش"</item>
+ <item msgid="1314234299552254621">"۱ میلیون در هر بافر گزارش"</item>
+ <item msgid="3606047780792894151">"۴ میلیون در هر بافر گزارش"</item>
+ <item msgid="5431354956856655120">"۱۶ میلیون در هر بافر گزارش"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"پویانمایی خاموش"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 2551ba5..e1a35f7 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامهای را برای نوشتن در حافظه خارجی واجد شرایط میکند"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیتها به قابل تغییر اندازه بودن"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیتها را برای چندپنجره قابل تغییر اندازه میکند."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبانگیری محلی"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبانگیری کامل رایانه درحال حاضر محافظت نمیشود"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"برای تغییر یا حذف گذرواژه برای نسخههای پشتیبان کامل دسکتاپ لمس کنید"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"غیرفعال است"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"همیشه روشن"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
index 40d0787..15e6e40 100644
--- a/packages/SettingsLib/res/values-fi/arrays.xml
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Käytä aina HDCP-tarkistusta"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kt"</item>
- <item msgid="505611754508988476">"256 kt"</item>
- <item msgid="6361286924268716397">"1 Mt"</item>
- <item msgid="6405203239560695266">"4 Mt"</item>
- <item msgid="3025431211013424097">"16 Mt"</item>
+ <item msgid="8665206199209698501">"Ei käytössä"</item>
+ <item msgid="1593289376502312923">"64 kt"</item>
+ <item msgid="487545340236145324">"256 kt"</item>
+ <item msgid="2423528675294333831">"1 Mt"</item>
+ <item msgid="180883774509476541">"4 Mt"</item>
+ <item msgid="2803199102589126938">"16 Mt"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kt"</item>
- <item msgid="3534782711045262344">"256 kt"</item>
- <item msgid="8085867209202153403">"1 Mt"</item>
+ <item msgid="6089470720451068364">"Ei käytössä"</item>
+ <item msgid="4622460333038586791">"64 kt"</item>
+ <item msgid="2212125625169582330">"256 kt"</item>
+ <item msgid="1704946766699242653">"1 Mt"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kt / lokipuskuri"</item>
- <item msgid="2822309747675758628">"256 kt / lokipuskuri"</item>
- <item msgid="6699306198357496731">"1 Mt / lokipuskuri"</item>
- <item msgid="5748528643937500349">"4 Mt / lokipuskuri"</item>
- <item msgid="1978629051085111592">"16 Mt / lokipuskuri"</item>
+ <item msgid="6921048829791179331">"Ei käytössä"</item>
+ <item msgid="2969458029344750262">"64 kt / lokipuskuri"</item>
+ <item msgid="1342285115665698168">"256 kt / lokipuskuri"</item>
+ <item msgid="1314234299552254621">"1 Mt / lokipuskuri"</item>
+ <item msgid="3606047780792894151">"4 Mt / lokipuskuri"</item>
+ <item msgid="5431354956856655120">"16 Mt / lokipuskuri"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animaatio pois käytöstä"</item>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 8a0e3b5..498f204 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Muuta tai vaihda tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Ei käytössä"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Aina käytössä"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automaattinen"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-käyttöönotto"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Määritä WebView-käyttöönotto"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Muunna tiedostojen salaukseksi"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Muunna…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tiedostot on jo salattu."</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
index 714dbe4..ab48103 100644
--- a/packages/SettingsLib/res/values-fr-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 ko"</item>
- <item msgid="505611754508988476">"256 ko"</item>
- <item msgid="6361286924268716397">"1 Mo"</item>
- <item msgid="6405203239560695266">"4 Mo"</item>
- <item msgid="3025431211013424097">"16 Mo"</item>
+ <item msgid="8665206199209698501">"Désactivé"</item>
+ <item msgid="1593289376502312923">"64 ko"</item>
+ <item msgid="487545340236145324">"256 ko"</item>
+ <item msgid="2423528675294333831">"1 Mo"</item>
+ <item msgid="180883774509476541">"4 Mo"</item>
+ <item msgid="2803199102589126938">"16 Mo"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 ko"</item>
- <item msgid="3534782711045262344">"256 ko"</item>
- <item msgid="8085867209202153403">"1 Mo"</item>
+ <item msgid="6089470720451068364">"Désactivé"</item>
+ <item msgid="4622460333038586791">"64 ko"</item>
+ <item msgid="2212125625169582330">"256 ko"</item>
+ <item msgid="1704946766699242653">"1 Mo"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"1 ko/tampon journal"</item>
- <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
- <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
- <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
- <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+ <item msgid="6921048829791179331">"Désactivé"</item>
+ <item msgid="2969458029344750262">"64 ko/tampon journal"</item>
+ <item msgid="1342285115665698168">"256 Ko/tampon journal"</item>
+ <item msgid="1314234299552254621">"1 Mo/tampon journal"</item>
+ <item msgid="3606047780792894151">"4 Mo/tampon journal"</item>
+ <item msgid="5431354956856655120">"16 Mo/tampon journal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f2c79de..b32bfb7 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Toujours actif"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré par un fichier"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index a8bed69..1cfd3d4 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Toujours utiliser la vérification HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 Ko"</item>
- <item msgid="505611754508988476">"256 Ko"</item>
- <item msgid="6361286924268716397">"1 Mo"</item>
- <item msgid="6405203239560695266">"4 Mo"</item>
- <item msgid="3025431211013424097">"16 Mo"</item>
+ <item msgid="8665206199209698501">"Désactivé"</item>
+ <item msgid="1593289376502312923">"64 Ko"</item>
+ <item msgid="487545340236145324">"256 Ko"</item>
+ <item msgid="2423528675294333831">"1 Mo"</item>
+ <item msgid="180883774509476541">"4 Mo"</item>
+ <item msgid="2803199102589126938">"16 Mo"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 Ko"</item>
- <item msgid="3534782711045262344">"256 Ko"</item>
- <item msgid="8085867209202153403">"1 Mo"</item>
+ <item msgid="6089470720451068364">"Désactivé"</item>
+ <item msgid="4622460333038586791">"64 Ko"</item>
+ <item msgid="2212125625169582330">"256 Ko"</item>
+ <item msgid="1704946766699242653">"1 Mo"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 Ko/tampon journal"</item>
- <item msgid="2822309747675758628">"256 Ko/tampon journal"</item>
- <item msgid="6699306198357496731">"1 Mo/tampon journal"</item>
- <item msgid="5748528643937500349">"4 Mo/tampon journal"</item>
- <item msgid="1978629051085111592">"16 Mo/tampon journal"</item>
+ <item msgid="6921048829791179331">"Désactivé"</item>
+ <item msgid="2969458029344750262">"64 Ko par tampon journal"</item>
+ <item msgid="1342285115665698168">"256 Ko par tampon journal"</item>
+ <item msgid="1314234299552254621">"1 Mo par tampon journal"</item>
+ <item msgid="3606047780792894151">"4 Mo par tampon journal"</item>
+ <item msgid="5431354956856655120">"16 Mo par tampon journal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animation désactivée"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 95e8804..0190454 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Désactivé"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Toujours activé"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatique"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Mise en œuvre WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Définir la mise en œuvre WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir en chiffrement basé sur un fichier"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Déjà chiffré via un fichier"</string>
diff --git a/packages/SettingsLib/res/values-gl-rES/arrays.xml b/packages/SettingsLib/res/values-gl-rES/arrays.xml
index 606e6f6..01b8fdf 100644
--- a/packages/SettingsLib/res/values-gl-rES/arrays.xml
+++ b/packages/SettingsLib/res/values-gl-rES/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar sempre a comprobación HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desactivado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desactivado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Búfer 64 K rexistro"</item>
- <item msgid="2822309747675758628">"Búfer 256 K rexist."</item>
- <item msgid="6699306198357496731">"Búfer 1 M rexistro"</item>
- <item msgid="5748528643937500349">"Búfer 4 M rexistro"</item>
- <item msgid="1978629051085111592">"Búfer 16 M rexistro"</item>
+ <item msgid="6921048829791179331">"Desactivado"</item>
+ <item msgid="2969458029344750262">"64 K por búfer de rexistro"</item>
+ <item msgid="1342285115665698168">"256 K por búfer de rexistro"</item>
+ <item msgid="1314234299552254621">"1 M por búfer de rexistro"</item>
+ <item msgid="3606047780792894151">"4 M por búfer de rexistro"</item>
+ <item msgid="5431354956856655120">"16 M por búfer de rexistro"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animación desactivada"</item>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index df58657..0efe805 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Fai que calquera aplicación se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desactivado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre activada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementación de WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter no encriptado baseado en ficheiros"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Xa se encriptou o ficheiro"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/arrays.xml b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
index c7d62c5..92cbb2d 100644
--- a/packages/SettingsLib/res/values-gu-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"હંમેશા HDCP તપાસનો ઉપયોગ કરો"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"બંધ"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"બંધ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"લૉગ બફર દીઠ 64K"</item>
- <item msgid="2822309747675758628">"લૉગ દીઠ 256K બફર"</item>
- <item msgid="6699306198357496731">"લૉગ બફર દીઠ 1M"</item>
- <item msgid="5748528643937500349">"લૉગ બફર દીઠ 4M"</item>
- <item msgid="1978629051085111592">"પ્રતિ લૉગ બફર 16M"</item>
+ <item msgid="6921048829791179331">"બંધ"</item>
+ <item msgid="2969458029344750262">"લૉગ બફર દીઠ 64K"</item>
+ <item msgid="1342285115665698168">"લૉગ બફર દીઠ 256K"</item>
+ <item msgid="1314234299552254621">"લૉગ બફર દીઠ 1M"</item>
+ <item msgid="3606047780792894151">"લૉગ બફર દીઠ 4M"</item>
+ <item msgid="5431354956856655120">"લૉગ બફર દીઠ 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"એનિમેશન બંધ"</item>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index d4db078..4b72648 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"મુક્તાકાર વિંડોઝ સક્ષમ કરો"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક મુક્તાકાર વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ડેસ્કટૉપ બેકઅપ પાસવર્ડ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ હાલમાં સુરક્ષિત નથી"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટચ કરો"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"અક્ષમ કરેલ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"હંમેશાં ચાલુ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"સ્વચલિત"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView અમલીકરણ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView અમલીકરણ સેટ કરો"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ફાઇલ એન્ક્રિપ્શનમાં રૂપાંતરિત કરો"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"રૂપાંતરિત કરો..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ફાઇલ પહેલેથી જ એન્ક્રિપ્ટ કરેલ છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
index 883e997..8aa98a1f 100644
--- a/packages/SettingsLib/res/values-hi/arrays.xml
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"हमेशा HDCP जांच का उपयोग करें"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"बंद"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"बंद"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K प्रति लॉग बफ़र"</item>
- <item msgid="2822309747675758628">"256K प्रति लॉग बफ़र"</item>
- <item msgid="6699306198357496731">"1M प्रति लॉग बफ़र"</item>
- <item msgid="5748528643937500349">"4M प्रति लॉग बफ़र"</item>
- <item msgid="1978629051085111592">"16M प्रति लॉग बफ़र"</item>
+ <item msgid="6921048829791179331">"बंद"</item>
+ <item msgid="2969458029344750262">"64K प्रति लॉग बफ़र"</item>
+ <item msgid="1342285115665698168">"256K प्रति लॉग बफ़र"</item>
+ <item msgid="1314234299552254621">"1M प्रति लॉग बफ़र"</item>
+ <item msgid="3606047780792894151">"4M प्रति लॉग बफ़र"</item>
+ <item msgid="5431354956856655120">"16M प्रति लॉग बफ़र"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"एनिमेशन बंद"</item>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index b6e5d7d..5224c38 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्य बन जाता है"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"एकाधिक-विंडो के लिए सभी गतिविधियों के आकार को बदले जाने योग्य बनाता है, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बैकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बैकअप वर्तमान में सुरक्षित नहीं हैं"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटॉप के पूर्ण बैकअप के पासवर्ड को बदलने या निकालने के लिए स्पर्श करें."</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"अक्षम"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"हमेशा चालू"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट करें"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फ़ाइल एन्क्रिप्शन में रूपांतरित करें"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करें..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फ़ाइल पहले से एन्क्रिप्ट की हुई है"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index d51f82d..db460c7 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Uvijek upotrebljavaj HDCP provjeru"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Isključeno"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Isključeno"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB po međusprem."</item>
- <item msgid="2822309747675758628">"256 KB po međuspr."</item>
- <item msgid="6699306198357496731">"1 MB po međusprem."</item>
- <item msgid="5748528643937500349">"4 MB po međusprem."</item>
- <item msgid="1978629051085111592">"16 MB po međusprem."</item>
+ <item msgid="6921048829791179331">"Isključeno"</item>
+ <item msgid="2969458029344750262">"64 KB po međusprem. zapisnika"</item>
+ <item msgid="1342285115665698168">"256 KB po međusprem. zapisnika"</item>
+ <item msgid="1314234299552254621">"1 MB po međusprem. zapisnika"</item>
+ <item msgid="3606047780792894151">"4 MB po međusprem. zapisnika"</item>
+ <item msgid="5431354956856655120">"16 MB po međusprem. zapisnika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija isključena"</item>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index f8434eb..5cde233 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Odaberite za promjenu ili uklanjanje zaporke u potpunim sigurnosnim kopijama na stolnom računalu"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Onemogućeno"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Uvijek uključeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatska"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacija WebViewa"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Postavi implementaciju WebViewa"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Pretvori u enkripciju datoteka"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pretvori…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkripcija datoteka već je izvršena"</string>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
index 03c9ed7..0d201b5 100644
--- a/packages/SettingsLib/res/values-hu/arrays.xml
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Mindig használjon HDCP ellenőrzést"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Ki"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Ki"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB/naplópuffer"</item>
- <item msgid="2822309747675758628">"256 KB/naplópuffer"</item>
- <item msgid="6699306198357496731">"1 MB/naplópuffer"</item>
- <item msgid="5748528643937500349">"4 MB/naplópuffer"</item>
- <item msgid="1978629051085111592">"16 MB/naplópuffer"</item>
+ <item msgid="6921048829791179331">"Ki"</item>
+ <item msgid="2969458029344750262">"64 KB/naplópuffer"</item>
+ <item msgid="1342285115665698168">"256 KB/naplópuffer"</item>
+ <item msgid="1314234299552254621">"1 MB/naplópuffer"</item>
+ <item msgid="3606047780792894151">"4 MB/naplópuffer"</item>
+ <item msgid="5431354956856655120">"16 MB/naplópuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animáció ki"</item>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 636f88a..3559f1e 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tevékenységek átméretezésének kényszerítése"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Lehetővé teszi, hogy az összes tevékenység átméretezhető legyen a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Szabad formájú ablakok engedélyezése"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Engedélyezi a kísérleti jellegű, szabad formájú ablakok támogatását."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Asztali mentés jelszava"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Érintse meg, ha módosítaná vagy eltávolítaná a jelszót az asztali teljes mentésekhez"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Kikapcsolva"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Mindig bekapcsolva"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatikus"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-megvalósítás"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-megvalósítás beállítása"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertálás fájlalapú titkosításra"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertálás…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Már fájlalapú titkosítást használ"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
index 41143de..0755a8a 100644
--- a/packages/SettingsLib/res/values-hy-rAM/arrays.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Միշտ օգտագործել HDCP ստուգումը"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64ԿԲ"</item>
- <item msgid="505611754508988476">"256ԿԲ"</item>
- <item msgid="6361286924268716397">"1ՄԲ"</item>
- <item msgid="6405203239560695266">"4ՄԲ"</item>
- <item msgid="3025431211013424097">"16ՄԲ"</item>
+ <item msgid="8665206199209698501">"Անջատված է"</item>
+ <item msgid="1593289376502312923">"64ԿԲ"</item>
+ <item msgid="487545340236145324">"256ԿԲ"</item>
+ <item msgid="2423528675294333831">"1ՄԲ"</item>
+ <item msgid="180883774509476541">"4ՄԲ"</item>
+ <item msgid="2803199102589126938">"16ՄԲ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64ԿԲ"</item>
- <item msgid="3534782711045262344">"256ԿԲ"</item>
- <item msgid="8085867209202153403">"1ՄԲ"</item>
+ <item msgid="6089470720451068364">"Անջատված է"</item>
+ <item msgid="4622460333038586791">"64ԿԲ"</item>
+ <item msgid="2212125625169582330">"256ԿԲ"</item>
+ <item msgid="1704946766699242653">"1ՄԲ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Պահնակ՝ առավ. 64ԿԲ"</item>
- <item msgid="2822309747675758628">"Պահնակ՝ առավ. 256ԿԲ"</item>
- <item msgid="6699306198357496731">"Պահնակ՝ առավ. 1ՄԲ"</item>
- <item msgid="5748528643937500349">"Պահնակ՝ առավ. 4ՄԲ"</item>
- <item msgid="1978629051085111592">"Պահնակ՝ առավ. 16ՄԲ"</item>
+ <item msgid="6921048829791179331">"Անջատված է"</item>
+ <item msgid="2969458029344750262">"Պահնակ՝ առավ. 64ԿԲ"</item>
+ <item msgid="1342285115665698168">"Պահնակ՝ առավ. 256ԿԲ"</item>
+ <item msgid="1314234299552254621">"Պահնակ՝ առավ. 1ՄԲ"</item>
+ <item msgid="3606047780792894151">"Պահնակ՝ առավ. 4ՄԲ"</item>
+ <item msgid="5431354956856655120">"Պահնակ՝ առավ. 16ՄԲ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Անջատել շարժապատկերը"</item>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index a2b901a..42c9a05 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Աշխատասեղանի ամբողջական պահուստավորման համար ընտրել փոխել կամ հեռացնել գաղտնաբառը"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Անջատված"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Միշտ միացված"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Ավտոմատ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-ի իրականացում"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ընտրեք WebView-ի իրականացումը"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Վերածել ֆայլային գաղտնագրման"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Փոխարկել…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ֆայլային գաղտնագրումն արդեն կատարվել է"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 5aadc13..166efd5 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Selalu gunakan pemeriksaan HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Nonaktif"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Nonaktif"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/penyangga log"</item>
- <item msgid="2822309747675758628">"256 K/penyangga log"</item>
- <item msgid="6699306198357496731">"1 M/penyangga log"</item>
- <item msgid="5748528643937500349">"4 M/penyangga log"</item>
- <item msgid="1978629051085111592">"16 M/penyangga log"</item>
+ <item msgid="6921048829791179331">"Nonaktif"</item>
+ <item msgid="2969458029344750262">"64 K/penyangga log"</item>
+ <item msgid="1342285115665698168">"256 K/penyangga log"</item>
+ <item msgid="1314234299552254621">"1 M/penyangga log"</item>
+ <item msgid="3606047780792894151">"4 M/penyangga log"</item>
+ <item msgid="5431354956856655120">"16 M/penyangga log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi mati"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index f4fbe1a..6988a73 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dinonaktifkan"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Selalu aktif"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatis"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Penerapan WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setel penerapan WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konversi ke enkripsi file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konversi..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah dienkripsi berbasis file"</string>
diff --git a/packages/SettingsLib/res/values-is-rIS/arrays.xml b/packages/SettingsLib/res/values-is-rIS/arrays.xml
index bbc7aec6..6024e30 100644
--- a/packages/SettingsLib/res/values-is-rIS/arrays.xml
+++ b/packages/SettingsLib/res/values-is-rIS/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Nota alltaf HDCP-eftirlit"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 k"</item>
- <item msgid="505611754508988476">"256 k"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Slökkt"</item>
+ <item msgid="1593289376502312923">"64 k"</item>
+ <item msgid="487545340236145324">"256 k"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 k"</item>
- <item msgid="3534782711045262344">"256 k"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Slökkt"</item>
+ <item msgid="4622460333038586791">"64 k"</item>
+ <item msgid="2212125625169582330">"256 k"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 k/biðminni"</item>
- <item msgid="2822309747675758628">"256 k/biðminni"</item>
- <item msgid="6699306198357496731">"1 M/biðminni"</item>
- <item msgid="5748528643937500349">"4 M/biðminni"</item>
- <item msgid="1978629051085111592">"16 M/biðminni"</item>
+ <item msgid="6921048829791179331">"Slökkt"</item>
+ <item msgid="2969458029344750262">"64 k/biðminni"</item>
+ <item msgid="1342285115665698168">"256 k/biðminni"</item>
+ <item msgid="1314234299552254621">"1 M/biðminni"</item>
+ <item msgid="3606047780792894151">"4 M/biðminni"</item>
+ <item msgid="5431354956856655120">"16 M/biðminni"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Slökkt á hreyfiáhrifum"</item>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 4139e6e..8d912e9 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Snertu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Óvirkt"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltaf kveikt"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Sjálfvirkt"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Innleiðing WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Stilla innleiðingu WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Umbreyta í dulkóðun skráa"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Umbreyta…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Þegar dulkóðað á grundvelli skráa"</string>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
index 686d61d..d64ec06 100644
--- a/packages/SettingsLib/res/values-it/arrays.xml
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Usa sempre la verifica HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Non attiva"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Non attiva"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB/buffer log"</item>
- <item msgid="2822309747675758628">"256 kB/buffer log"</item>
- <item msgid="6699306198357496731">"1 MB/buffer log"</item>
- <item msgid="5748528643937500349">"4 MB/buffer log"</item>
- <item msgid="1978629051085111592">"16 MB/buffer log"</item>
+ <item msgid="6921048829791179331">"Non attiva"</item>
+ <item msgid="2969458029344750262">"64 kB/buffer log"</item>
+ <item msgid="1342285115665698168">"256 kB/buffer log"</item>
+ <item msgid="1314234299552254621">"1 MB/buffer log"</item>
+ <item msgid="3606047780792894151">"4 MB/buffer log"</item>
+ <item msgid="5431354956856655120">"16 MB/buffer log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animazione disattivata"</item>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 33a15d4..2d98a74 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rende l\'app idonea all\'installaz. su mem. esterna, senza considerare i valori manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Rende il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Attiva finestre a forma libera"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Attiva il supporto per le finestre a forma libera sperimentali."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Password di backup desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"I backup desktop completi non sono attualmente protetti."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Disattivato"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre attivo"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatico"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementazione di WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Imposta l\'implementazione di WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converti in crittografia basata su file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converti..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Crittografia su base file già eseguita"</string>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 24a40b9..01127c6 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"תמיד השתמש בבדיקת HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"כבוי"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"כבוי"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K לכל מאגר יומן"</item>
- <item msgid="2822309747675758628">"256K לכל מאגר יומן"</item>
- <item msgid="6699306198357496731">"1M לכל מאגר יומן"</item>
- <item msgid="5748528643937500349">"4M לכל מאגר יומן"</item>
- <item msgid="1978629051085111592">"16M לכל מאגר יומן"</item>
+ <item msgid="6921048829791179331">"כבוי"</item>
+ <item msgid="2969458029344750262">"64K לכל מאגר יומן"</item>
+ <item msgid="1342285115665698168">"256K לכל מאגר יומן"</item>
+ <item msgid="1314234299552254621">"1M לכל מאגר יומן"</item>
+ <item msgid="3606047780792894151">"4M לכל מאגר יומן"</item>
+ <item msgid="5431354956856655120">"16M לכל מאגר יומן"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"אנימציה כבויה"</item>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 4a0870e..e175208 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"גע כדי לשנות או להסיר את הסיסמה עבור גיבויים מלאים בשולחן העבודה"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"מושבת"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"פועל תמיד"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"באופן אוטומטי"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"יישום WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"הגדרת יישום WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"המר להצפנת קבצים"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"המר..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"הצפנת קבצים כבר מוגדרת"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 6307a10..3426b5c 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCPチェックを常に使用する"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"OFF"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"OFF"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/ログバッファ"</item>
- <item msgid="2822309747675758628">"256K/ログバッファ"</item>
- <item msgid="6699306198357496731">"1M/ログバッファ"</item>
- <item msgid="5748528643937500349">"4M/ログバッファ"</item>
- <item msgid="1978629051085111592">"16M/ログバッファ"</item>
+ <item msgid="6921048829791179331">"OFF"</item>
+ <item msgid="2969458029344750262">"64 K / ログバッファ"</item>
+ <item msgid="1342285115665698168">"256 K / ログバッファ"</item>
+ <item msgid="1314234299552254621">"1 M / ログバッファ"</item>
+ <item msgid="3606047780792894151">"4 M / ログバッファ"</item>
+ <item msgid="5431354956856655120">"16 M / ログバッファ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"アニメーションオフ"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 4c043ac..bf9bf8a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -263,9 +267,9 @@
<item msgid="8280754435979370728">"目に自然な色"</item>
<item msgid="5363960654009010371">"デジタルコンテンツに最適な色"</item>
</string-array>
- <string name="inactive_apps_title" msgid="1317817863508274533">"無効なアプリ"</string>
- <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"無効。タップすると切り替わります。"</string>
- <string name="inactive_app_active_summary" msgid="4512911571954375968">"有効。タップすると切り替わります。"</string>
+ <string name="inactive_apps_title" msgid="1317817863508274533">"休止中のアプリ"</string>
+ <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"休止中。タップすると切り替わります。"</string>
+ <string name="inactive_app_active_summary" msgid="4512911571954375968">"実行中。タップすると切り替わります。"</string>
<string name="runningservices_settings_title" msgid="8097287939865165213">"実行中のサービス"</string>
<string name="runningservices_settings_summary" msgid="854608995821032748">"現在実行中のサービスを表示して制御する"</string>
<string name="night_mode_title" msgid="2594133148531256513">"夜間モード"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"無効"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"常にON"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView の実装"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView の実装の設定"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ファイル暗号化に変換する"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"変換…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ファイルは既に暗号化済みです"</string>
diff --git a/packages/SettingsLib/res/values-ka-rGE/arrays.xml b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
index ac627a2..4b6f78b 100644
--- a/packages/SettingsLib/res/values-ka-rGE/arrays.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ყოველთვის გამოიყენე HDCP შემოწმება"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"გამორთული"</item>
+ <item msgid="1593289376502312923">"64 კბაიტი"</item>
+ <item msgid="487545340236145324">"256 კბაიტი"</item>
+ <item msgid="2423528675294333831">"1 მბაიტი"</item>
+ <item msgid="180883774509476541">"4 მბაიტი"</item>
+ <item msgid="2803199102589126938">"16 მბაიტი"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"გამორთული"</item>
+ <item msgid="4622460333038586791">"64 კბაიტი"</item>
+ <item msgid="2212125625169582330">"256 კბაიტი"</item>
+ <item msgid="1704946766699242653">"1 მბაიტი"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K / ჟურნ. ბუფერზე"</item>
- <item msgid="2822309747675758628">"256K/ჟურნ. ბუფერზე"</item>
- <item msgid="6699306198357496731">"1M / ჟურნ. ბუფერზე"</item>
- <item msgid="5748528643937500349">"4M / ჟურნ. ბუფერზე"</item>
- <item msgid="1978629051085111592">"16M / ჟურნ. ბუფერზე"</item>
+ <item msgid="6921048829791179331">"გამორთული"</item>
+ <item msgid="2969458029344750262">"64 კბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="1342285115665698168">"256 კბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="1314234299552254621">"1 მბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="3606047780792894151">"4 მბაიტი / ჟურნალის ბუფერი"</item>
+ <item msgid="5431354956856655120">"16 მბაიტი / ჟურნალის ბუფერი"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ანიმაციის გამორთვა"</item>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index 1ea79bf..da9d204 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"გამორთულია"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ყოველთვის ჩართული"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ავტომატური"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView რეალიზაცია"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView რეალიზაციის დაყენება"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ფაილების დაშიფვრაზე გარდაქმნა"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"გარდაქმნა…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"უკვე დაშიფრულია ფაილების დონეზე"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
index b994eb7..43afb2f 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Әрқашан HDCP (жоғары кең жолақты сандық мазмұн қорғаушы) тексерулерін қолданыңыз"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Өшірулі"</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Өшірулі"</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Әр журнал буферіне 64 КБ"</item>
- <item msgid="2822309747675758628">"Әр журнал буферіне 256 КБ"</item>
- <item msgid="6699306198357496731">"Әр журнал буферіне 1 МБ"</item>
- <item msgid="5748528643937500349">"Әр журнал буферіне 4 МБ"</item>
- <item msgid="1978629051085111592">"Әр журнал буферіне 16 МБ"</item>
+ <item msgid="6921048829791179331">"Өшірулі"</item>
+ <item msgid="2969458029344750262">"Әр журнал буферіне 64 КБ"</item>
+ <item msgid="1342285115665698168">"Әр журнал буферіне 256 КБ"</item>
+ <item msgid="1314234299552254621">"Әр журнал буферіне 1 МБ"</item>
+ <item msgid="3606047780792894151">"Әр журнал буферіне 4 МБ"</item>
+ <item msgid="5431354956856655120">"Әр журнал буферіне 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Aнимация өшірілген"</item>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index c6a2768..549711c 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Жұмыс үстелінің толық сақтық көшірмесінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Өшірілген"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Әрқашан қосулы"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Aвтоматты"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ендіру"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ендіруін орнату"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлды шифрлауға түрлендіру"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Түрлендіру..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл шифрланып қойылған"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/arrays.xml b/packages/SettingsLib/res/values-km-rKH/arrays.xml
index 50c1299..63921bc 100644
--- a/packages/SettingsLib/res/values-km-rKH/arrays.xml
+++ b/packages/SettingsLib/res/values-km-rKH/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ប្រើការពិនិត្យ HDCP ជានិច្ច"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"បិទ"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"បិទ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K per log buffer"</item>
- <item msgid="2822309747675758628">"256K per log buffer"</item>
- <item msgid="6699306198357496731">"1M per log buffer"</item>
- <item msgid="5748528643937500349">"4M per log buffer"</item>
- <item msgid="1978629051085111592">"16M per log buffer"</item>
+ <item msgid="6921048829791179331">"បិទ"</item>
+ <item msgid="2969458029344750262">"64K per log buffer"</item>
+ <item msgid="1342285115665698168">"256K per log buffer"</item>
+ <item msgid="1314234299552254621">"1M per log buffer"</item>
+ <item msgid="3606047780792894151">"4M per log buffer"</item>
+ <item msgid="5431354956856655120">"16M per log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"បិទចលនា"</item>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 3e91925..aed4365 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ពាក្យសម្ងាត់បម្រុងទុកលើផ្ទៃតុ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការបម្រុងទុកពេញលេញលើផ្ទៃតុបច្ចុប្បន្នមិនត្រូវបានការពារទេ។"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ប៉ះ ដើម្បីប្ដូរ ឬលុបពាក្យសម្ងាត់សម្រាប់ការបម្រុងទុកពេញលេញលើផ្ទៃតុ"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"បានបិទ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"បើកជានិច្ច"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ស្វ័យប្រវត្តិ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"ការប្រតិបត្តិ WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"កំណត់ការប្រតិបត្តិ WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"បម្លែងទៅជាការអ៊ីនគ្រីបឯកសារ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"បម្លែង…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"បានអ៊ីនគ្រីបឯកសាររួចហើយ"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/arrays.xml b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
index fe04d28..e1e69f7 100644
--- a/packages/SettingsLib/res/values-kn-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP ಪರಿಶೀಲನೆಯನ್ನು ಯಾವಾಗಲೂ ಬಳಸು"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ಆಫ್"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ಆಫ್"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 64K"</item>
- <item msgid="2822309747675758628">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 256K"</item>
- <item msgid="6699306198357496731">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 1M"</item>
- <item msgid="5748528643937500349">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 4M"</item>
- <item msgid="1978629051085111592">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 16M"</item>
+ <item msgid="6921048829791179331">"ಆಫ್"</item>
+ <item msgid="2969458029344750262">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 64K"</item>
+ <item msgid="1342285115665698168">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 256K"</item>
+ <item msgid="1314234299552254621">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 1M"</item>
+ <item msgid="3606047780792894151">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 4M"</item>
+ <item msgid="5431354956856655120">"ಪ್ರತಿ ಲಾಗ್ ಬಫರ್ಗೆ 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ಆನಿಮೇಶನ್ ಆಫ್"</item>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 4d1f9e1..50e5955 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡುತ್ತದೆ."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ಡೆಸ್ಕ್ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್ವರ್ಡ್"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ಡೆಸ್ಕ್ಟಾಪ್ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್ಗಳಿಗೆ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಸ್ಪರ್ಶಿಸಿ"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ಯಾವಾಗಲೂ ಆನ್"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ಸ್ವಯಂಚಾಲಿತ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ಅನುಷ್ಠಾನಗೊಳಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ಫೈಲ್ ಎನ್ಕ್ರಿಪ್ಶನ್ಗೆ ಪರಿವರ್ತಿಸು"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ಪರಿವರ್ತಿಸು…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ಫೈಲ್ ಈಗಾಗಲೇ ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
index a8d548ff..3e8867e 100644
--- a/packages/SettingsLib/res/values-ko/arrays.xml
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"항상 HDCP 확인 사용"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"사용 안함"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"사용 안함"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"로그 버퍼당 64K"</item>
- <item msgid="2822309747675758628">"로그 버퍼당 256K"</item>
- <item msgid="6699306198357496731">"로그 버퍼당 1M"</item>
- <item msgid="5748528643937500349">"로그 버퍼당 4M"</item>
- <item msgid="1978629051085111592">"로그 버퍼당 16M"</item>
+ <item msgid="6921048829791179331">"사용 안함"</item>
+ <item msgid="2969458029344750262">"로그 버퍼당 64K"</item>
+ <item msgid="1342285115665698168">"로그 버퍼당 256K"</item>
+ <item msgid="1314234299552254621">"로그 버퍼당 1M"</item>
+ <item msgid="3606047780792894151">"로그 버퍼당 4M"</item>
+ <item msgid="5431354956856655120">"로그 버퍼당 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"애니메이션 사용 안함"</item>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index c4ab084..ea5dc00 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"데스크톱 백업 비밀번호"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 터치하세요."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"사용 안함"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"항상 사용"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"자동"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 구현"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView 구현 설정"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"파일 암호화로 변환"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"변환..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"파일이 이미 암호화됨"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/arrays.xml b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
index 7ec569e..34c713e 100644
--- a/packages/SettingsLib/res/values-ky-rKG/arrays.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Ар дайым HDCP текшерүү колдонулсун"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Өчүк"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Өчүк"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K каттоо буфери үчүн"</item>
- <item msgid="2822309747675758628">"256 K каттоо буфери үчүн"</item>
- <item msgid="6699306198357496731">"1 M каттоо буфери үчүн"</item>
- <item msgid="5748528643937500349">"4 M каттоо буфери үчүн"</item>
- <item msgid="1978629051085111592">"16 M каттоо буфери үчүн"</item>
+ <item msgid="6921048829791179331">"Өчүк"</item>
+ <item msgid="2969458029344750262">"Буфер: 64КБ ашпашы керек"</item>
+ <item msgid="1342285115665698168">"Буфер: 256КБ ашпашы керек"</item>
+ <item msgid="1314234299552254621">"Буфер: 1М ашпашы керек"</item>
+ <item msgid="3606047780792894151">"Буфер: 4М ашпашы керек"</item>
+ <item msgid="5431354956856655120">"Буфер: 16М ашпашы керек"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимацияны өчүрүү"</item>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 77c5ab8..6a47406 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Тийип, компүтердеги толук бэкаптын сырсөзүн өзгөртүңүз же жок кылыңыз"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Өчүрүлгөн"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Ар дайым күйгүзүлгөн"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматтык"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/arrays.xml b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
index 6422174..312ecc0 100644
--- a/packages/SettingsLib/res/values-lo-rLA/arrays.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ໃຊ້ການກວດສອບ HDCP ສະເໝີ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ປິດ"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ປິດ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"ບັບເຟີ 64K ຕໍ່ລັອກ"</item>
- <item msgid="2822309747675758628">"ບັບເຟີ 256K ຕໍ່ລັອກ"</item>
- <item msgid="6699306198357496731">"ບັບເຟີ 1M ຕໍ່ລັອກ"</item>
- <item msgid="5748528643937500349">"ບັບເຟີ 4M ຕໍ່ລັອກ"</item>
- <item msgid="1978629051085111592">"ບັບເຟີ 16M ຕໍ່ລັອກ"</item>
+ <item msgid="6921048829791179331">"ປິດ"</item>
+ <item msgid="2969458029344750262">"ບັບເຟີ 64K ຕໍ່ບັນທຶກ"</item>
+ <item msgid="1342285115665698168">"ບັບເຟີ 256K ຕໍ່ບັນທຶກ"</item>
+ <item msgid="1314234299552254621">"ບັບເຟີ 1M ຕໍ່ບັນທຶກ"</item>
+ <item msgid="3606047780792894151">"ບັບເຟີ 4M ຕໍ່ບັນທຶກ"</item>
+ <item msgid="5431354956856655120">"ບັບເຟີ 16M ຕໍ່ບັນທຶກ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ປິດອະນິເມຊັນ"</item>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 806e1c0..538a38c 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດໃຫ້ທຸກແອັບມີສິດໄດ້ຮັບການຂຽນໃສ່ບ່ອນຈັດເກັບພາຍນອກ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ບັງຄັງໃຫ້ກິດຈະກຳປ່ຽນຂະໜາດໄດ້"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດໃຫ້ທຸກກິດຈະກຳປ່ຽນຂະໜາດໄດ້ສຳລັບຫຼາຍໜ້າຕ່າງ, ໂດຍບໍ່ຄຳນຶງເຖິງຄ່າທີ່ຈະແຈ້ງ."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບຍັງບໍ່ໄດ້ຮັບການປ້ອງກັນໃນເວລານີ້"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ປິດໃຊ້ງານແລ້ວ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ເປີດຕະຫຼອດ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ອັດຕະໂນມັດ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"ການຈັດຕັ້ງປະຕິບັດ WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ຕັ້ງການຈັດຕັ້ງປະຕິບັດ WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ປ່ຽນເປັນການເຂົ້າລະຫັດໄຟລ໌"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ປ່ຽນ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ໄຟລ໌ເຂົ້າລະຫັດຮຽບຮ້ອຍແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
index 0d20a8a..76ae3fb 100644
--- a/packages/SettingsLib/res/values-lt/arrays.xml
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Visada naudoti HDCP tikrinimą"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Išjungta"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Išjungta"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB žurn. bufer."</item>
- <item msgid="2822309747675758628">"256 KB žurn. bufer."</item>
- <item msgid="6699306198357496731">"1 MB žurn. bufer."</item>
- <item msgid="5748528643937500349">"4 MB žurn. bufer."</item>
- <item msgid="1978629051085111592">"16 MB žurn. bufer."</item>
+ <item msgid="6921048829791179331">"Išjungta"</item>
+ <item msgid="2969458029344750262">"64 KB žurnalo buferis"</item>
+ <item msgid="1342285115665698168">"256 KB žurnalo buferis"</item>
+ <item msgid="1314234299552254621">"1 MB žurnalo buferis"</item>
+ <item msgid="3606047780792894151">"4 MB žurnalo buferis"</item>
+ <item msgid="5431354956856655120">"16 MB žurnalo buferis"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija išjungta"</item>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 0b04f53..014a6fb 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Nustatoma, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Jei norite pakeisti ar pašalinti visų vietinių atsarginių kopijų slaptažodį, palieskite"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Išjungta"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Visada įjungta"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatinė"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"„WebView“ diegimas"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"„WebView“ diegimo nustatymas"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuoti į failų šifruotę"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuoti…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau konvertuota į failų šifruotę"</string>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
index a033d1b..03aff8c 100644
--- a/packages/SettingsLib/res/values-lv/arrays.xml
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vienmēr izmantot HDCP pārbaudi"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Izslēgts"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Izslēgts"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB žurn. buferis"</item>
- <item msgid="2822309747675758628">"256 KB žurn. buf."</item>
- <item msgid="6699306198357496731">"1 MB žurn. buferis"</item>
- <item msgid="5748528643937500349">"4 MB žurn. buferis"</item>
- <item msgid="1978629051085111592">"16 MB žurn. buferis"</item>
+ <item msgid="6921048829791179331">"Izslēgts"</item>
+ <item msgid="2969458029344750262">"64 KB vienam žurnāla buferim"</item>
+ <item msgid="1342285115665698168">"256 KB vienam žurnāla buferim"</item>
+ <item msgid="1314234299552254621">"1 MB vienam žurnāla buferim"</item>
+ <item msgid="3606047780792894151">"4 MB vienam žurnāla buferim"</item>
+ <item msgid="5431354956856655120">"16 MB vienam žurnāla buferim"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animācija ir izslēgta"</item>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index b955162..87da105 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem darbvirsmas dublējumiem."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Atspējots"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vienmēr ieslēgts"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automātiski"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ieviešana"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Iestatīt WebView ieviešanu"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Pārvērst par failu šifrējumu"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Pārvērst…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Jau šifrēts failu līmenī"</string>
diff --git a/packages/SettingsLib/res/values-mk-rMK/arrays.xml b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
index c97b577..588c21a 100644
--- a/packages/SettingsLib/res/values-mk-rMK/arrays.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Секогаш користи ХДЦП проверка"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Исклучено"</item>
+ <item msgid="1593289376502312923">"64.000"</item>
+ <item msgid="487545340236145324">"256.000"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64.000"</item>
- <item msgid="3534782711045262344">"256.000"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Исклучено"</item>
+ <item msgid="4622460333038586791">"64.000"</item>
+ <item msgid="2212125625169582330">"256.000"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/меѓумеморија"</item>
- <item msgid="2822309747675758628">"256 K/меѓумеморија"</item>
- <item msgid="6699306198357496731">"1 M/меѓумеморија"</item>
- <item msgid="5748528643937500349">"4 M/меѓумеморија"</item>
- <item msgid="1978629051085111592">"16 M/меѓумеморија"</item>
+ <item msgid="6921048829791179331">"Исклучено"</item>
+ <item msgid="2969458029344750262">"64 K/меѓумеморија"</item>
+ <item msgid="1342285115665698168">"256 K/меѓумеморија"</item>
+ <item msgid="1314234299552254621">"1 M/меѓумеморија"</item>
+ <item msgid="3606047780792894151">"4 M/меѓумеморија"</item>
+ <item msgid="5431354956856655120">"16 M/меѓумеморија"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимација"</item>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index f19b7b3..b588c2c 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -97,7 +97,7 @@
<string name="running_process_item_user_label" msgid="3129887865552025943">"Корисник: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="313159469856372621">"Поставени се некои стандардни вредности"</string>
<string name="launch_defaults_none" msgid="4241129108140034876">"Нема поставено стандардни вредности"</string>
- <string name="tts_settings" msgid="8186971894801348327">"Подесувања на текст-во-говор"</string>
+ <string name="tts_settings" msgid="8186971894801348327">"Поставки на текст-во-говор"</string>
<string name="tts_settings_title" msgid="1237820681016639683">"Излез текст-во-говор"</string>
<string name="tts_default_rate_title" msgid="6030550998379310088">"Брзина на говор"</string>
<string name="tts_default_rate_summary" msgid="4061815292287182801">"Брзина со која се кажува текстот"</string>
@@ -117,7 +117,7 @@
<string name="tts_status_requires_network" msgid="6042500821503226892">"<xliff:g id="LOCALE">%1$s</xliff:g> бара мрежно поврзување"</string>
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> не е поддржано"</string>
<string name="tts_status_checking" msgid="5339150797940483592">"Се проверува..."</string>
- <string name="tts_engine_settings_title" msgid="3499112142425680334">"Подесувања на <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
+ <string name="tts_engine_settings_title" msgid="3499112142425680334">"Поставки на <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
<string name="tts_engine_settings_button" msgid="1030512042040722285">"Стартувај подесувања на софтвер"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Претпочитан софтвер"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Општо"</string>
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ги прави сите активности да бидат со променлива големина за мултипрозорец, без разлика на вредностите на манифестот."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Резервна лозинка за работна површина"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Целосни резервни копии на работната површина кои во моментов не се заштитени"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Допрете за да се промени или отстрани лозинката за целосна резервна копија на работната површина"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Оневозможено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Секогаш вклучено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматски"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Воведување WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Поставете воведување WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертирајте до шифрирање датотеки"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертирај..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Датотеката е веќе шифрирана"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/arrays.xml b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
index 404b20a..f04cc65 100644
--- a/packages/SettingsLib/res/values-ml-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"എല്ലായ്പ്പോഴും HDCP പരിശോധന ഉപയോഗിക്കുക"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ഓഫ്"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ഓഫ്"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
- <item msgid="2822309747675758628">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
- <item msgid="6699306198357496731">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
- <item msgid="5748528643937500349">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
- <item msgid="1978629051085111592">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
+ <item msgid="6921048829791179331">"ഓഫ്"</item>
+ <item msgid="2969458029344750262">"ഓരോ ലോഗ് ബഫറിനും 64K"</item>
+ <item msgid="1342285115665698168">"ഓരോ ലോഗ് ബഫറിനും 256K"</item>
+ <item msgid="1314234299552254621">"ഓരോ ലോഗ് ബഫറിനും 1M"</item>
+ <item msgid="3606047780792894151">"ഓരോ ലോഗ് ബഫറിനും 4M"</item>
+ <item msgid="5431354956856655120">"ഓരോ ലോഗ് ബഫറിനും 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ആനിമേഷൻ ഓഫുചെയ്യുക"</item>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 373a00d..d76e87f7 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ഡെസ്ക്ടോപ്പ് ബാക്കപ്പ് പാസ്വേഡ്"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ഡെസ്ക്ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ സ്പർശിക്കുക"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"എല്ലായ്പ്പോഴും ഓണാണ്"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ഓട്ടോമാറ്റിക്"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView നടപ്പാക്കൽ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView നടപ്പാക്കൽ സജ്ജമാക്കുക"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ഫയൽ എൻക്രിപ്ഷനിലേക്ക് പരിവർത്തിപ്പിക്കുക"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"പരിവർത്തിപ്പിക്കുക…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ഇതിനകം തന്നെ ഫയൽ എൻക്രിപ്റ്റ് ചെയ്തു"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/arrays.xml b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
index c4c6d28..c4bbbcb 100644
--- a/packages/SettingsLib/res/values-mn-rMN/arrays.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Байнга HDCP шалгахыг ашиглах"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1М"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Идэвхгүй"</item>
+ <item msgid="1593289376502312923">"64000"</item>
+ <item msgid="487545340236145324">"256000"</item>
+ <item msgid="2423528675294333831">"1 сая"</item>
+ <item msgid="180883774509476541">"4 сая"</item>
+ <item msgid="2803199102589126938">"16 сая"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1М"</item>
+ <item msgid="6089470720451068364">"Идэвхгүй"</item>
+ <item msgid="4622460333038586791">"64000"</item>
+ <item msgid="2212125625169582330">"256000"</item>
+ <item msgid="1704946766699242653">"1 сая"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"лог буфер бүрт 64K"</item>
- <item msgid="2822309747675758628">"лог буфер бүрт 256K"</item>
- <item msgid="6699306198357496731">"лог буфер бүрт 1M"</item>
- <item msgid="5748528643937500349">"лог буфер бүрт 4M"</item>
- <item msgid="1978629051085111592">"лог буфер бүрт 16M"</item>
+ <item msgid="6921048829791179331">"Идэвхгүй"</item>
+ <item msgid="2969458029344750262">"лог буфер бүрт 64K"</item>
+ <item msgid="1342285115665698168">"лог буфер бүрт 256K"</item>
+ <item msgid="1314234299552254621">"лог буфер бүрт 1M"</item>
+ <item msgid="3606047780792894151">"лог буфер бүрт 4M"</item>
+ <item msgid="5431354956856655120">"лог буфер бүрт 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Дүрс амилуулалт идэвхгүй"</item>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 62e2c39..4aea631 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Десктоп дээрх бүрэн нөөшлөлтийн нууц үгийг өөрчлөх буюу арилгахын тулд хүрнэ үү"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Идэвхгүй"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Байнга асаалттай"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматаар"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView хэрэгжилт"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView хэрэгжилтийг тохируулах"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Файлын шифрлэлт болгон хөрвүүлэх"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Хөрвүүлэх..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Аль хэдийнэ файл шифрлэгдсэн"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/arrays.xml b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
index 70c1157..2f07389 100644
--- a/packages/SettingsLib/res/values-mr-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"नेहमी HDCP तपासणी वापरा"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"बंद"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"बंद"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"प्रति लॉग बफर 64K"</item>
- <item msgid="2822309747675758628">"प्रति लॉग बफर 256K"</item>
- <item msgid="6699306198357496731">"प्रति लॉग बफर 1M"</item>
- <item msgid="5748528643937500349">"प्रति लॉग बफर 4M"</item>
- <item msgid="1978629051085111592">"प्रति लॉग बफर 16M"</item>
+ <item msgid="6921048829791179331">"बंद"</item>
+ <item msgid="2969458029344750262">"प्रति लॉग बफर 64K"</item>
+ <item msgid="1342285115665698168">"प्रति लॉग बफर 256K"</item>
+ <item msgid="1314234299552254621">"प्रति लॉग बफर 1M"</item>
+ <item msgid="3606047780792894151">"प्रति लॉग बफर 4M"</item>
+ <item msgid="5431354956856655120">"प्रति लॉग बफर 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"अॅनिमेशन बंद"</item>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index cc3621a..ed57fb7 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्यासाठी पात्र बनविते"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"क्रियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढून टाकण्यासाठी स्पर्श करा"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"अक्षम केले"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"नेहमी चालू"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वयंचलित"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"वेबदृश्य अंमलबजावणी"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"वेबदृश्य अंमलबजावणी सेट करा"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाईल कूटबद्धीकरणावर रूपांतरित करा"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रूपांतरित करा..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"फाईल आधीपासून कूटबद्ध केली"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/arrays.xml b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
index 320fa9b..49f0f28 100644
--- a/packages/SettingsLib/res/values-ms-rMY/arrays.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sentiasa gunakan penyemakan HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Mati"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Mati"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K per penimbal log"</item>
- <item msgid="2822309747675758628">"256K per penimbal log"</item>
- <item msgid="6699306198357496731">"1M per penimbal log"</item>
- <item msgid="5748528643937500349">"4M per penimbal log"</item>
- <item msgid="1978629051085111592">"16M per penimbal log"</item>
+ <item msgid="6921048829791179331">"Mati"</item>
+ <item msgid="2969458029344750262">"64K per penimbal log"</item>
+ <item msgid="1342285115665698168">"256K per penimbal log"</item>
+ <item msgid="1314234299552254621">"1M per penimbal log"</item>
+ <item msgid="3606047780792894151">"4M per penimbal log"</item>
+ <item msgid="5431354956856655120">"16M per penimbal log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasi dimatikan"</item>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index babbefa..1f72d04 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh komputer meja"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dilumpuhkan"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sentiasa hidup"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatik"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Pelaksanaan WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Tetapkan pelaksanaan WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Tukar kepada penyulitan fail"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Tukar..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sudah disulitkan fail"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/arrays.xml b/packages/SettingsLib/res/values-my-rMM/arrays.xml
index 71b35ad..ad3a59f 100644
--- a/packages/SettingsLib/res/values-my-rMM/arrays.xml
+++ b/packages/SettingsLib/res/values-my-rMM/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP checkingအားအမြဲသုံးပါ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ပိတ်ပါ"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"၆၄K"</item>
- <item msgid="3534782711045262344">"၂၅၆K"</item>
- <item msgid="8085867209202153403">"၁M"</item>
+ <item msgid="6089470720451068364">"ပိတ်ပါ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K လော့ ဘာဖားတွက်"</item>
- <item msgid="2822309747675758628">"256K လော့ ဘာဖားတွက်"</item>
- <item msgid="6699306198357496731">"1M လော့ ဘာဖားတွက်"</item>
- <item msgid="5748528643937500349">"4M လော့ ဘာဖားတွက်"</item>
- <item msgid="1978629051085111592">"16M လော့ ဘာဖားတွက်"</item>
+ <item msgid="6921048829791179331">"ပိတ်ပါ"</item>
+ <item msgid="2969458029344750262">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 64K"</item>
+ <item msgid="1342285115665698168">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 256K"</item>
+ <item msgid="1314234299552254621">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 1M"</item>
+ <item msgid="3606047780792894151">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 4M"</item>
+ <item msgid="5431354956856655120">"မှတ်တမ်းယာယီကြားခံနယ်တစ်ခုလျှင် 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"လှုပ်ရှားသက်ဝင်မှုပုံများကိုပိတ်ပါ"</item>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index f293d4a..cd4812f 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"အလုပ်ခုံ တွင် အရန်သိမ်းဆည်းခြင်းအပြည့်လုပ်ရန် အတွက် စကားဝှက်ဖယ်ရန် သို့ ပြောင်းရန် တို့ထိပါ။"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ပိတ်ထား"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"အမြဲတမ်း ဖွင့်ထားရန်"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"အလိုအလျောက်"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView အကောင်အထည်ဖော်မှု"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView အကောင်အထည်ဖော်မှု သတ်မှတ်ပါ"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ဖိုင်လုံခြုံအောင်ပြုလုပ်ခြင်းသို့ ပြောင်းပါ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ပြောင်းရန်…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ဖိုင်ကို လုံခြုံအောင်ပြုလုပ်ပြီးပါပြီ"</string>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
index 0877f5c..8311db3 100644
--- a/packages/SettingsLib/res/values-nb/arrays.xml
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Bruk alltid HDCP-kontroll"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Av"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 000"</item>
- <item msgid="3534782711045262344">"256 000"</item>
- <item msgid="8085867209202153403">"1 million"</item>
+ <item msgid="6089470720451068364">"Av"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB pr loggbuffer"</item>
- <item msgid="2822309747675758628">"256 kB pr buffer"</item>
- <item msgid="6699306198357496731">"1 MB pr loggbuffer"</item>
- <item msgid="5748528643937500349">"4 MB pr loggbuffer"</item>
- <item msgid="1978629051085111592">"16 MB pr loggbuffer"</item>
+ <item msgid="6921048829791179331">"Av"</item>
+ <item msgid="2969458029344750262">"64K per loggbuffer"</item>
+ <item msgid="1342285115665698168">"256K per loggbuffer"</item>
+ <item msgid="1314234299552254621">"1M per loggbuffer"</item>
+ <item msgid="3606047780792894151">"4M per loggbuffer"</item>
+ <item msgid="5431354956856655120">"16M per loggbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasjon av"</item>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 2b461e7..ae0b15d 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Slått av"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisk"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Angi WebView-implementering"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertér til kryptert fil"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertér …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Allerede kryptert og lagret som fil"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/arrays.xml b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
index 99ec881..7468982 100644
--- a/packages/SettingsLib/res/values-ne-rNP/arrays.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"सधैँ HDCP जाँच प्रयोग गर्नुहोस्"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="1593289376502312923">"६४के"</item>
+ <item msgid="487545340236145324">"२५६के"</item>
+ <item msgid="2423528675294333831">"१एम"</item>
+ <item msgid="180883774509476541">"४एम"</item>
+ <item msgid="2803199102589126938">"१६एम"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"६४K"</item>
- <item msgid="3534782711045262344">"२५६K"</item>
- <item msgid="8085867209202153403">"१ मेगा पिक्सेल"</item>
+ <item msgid="6089470720451068364">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="4622460333038586791">"६४के"</item>
+ <item msgid="2212125625169582330">"२५६के"</item>
+ <item msgid="1704946766699242653">"१एम"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K प्रति लग बफर"</item>
- <item msgid="2822309747675758628">"256K प्रति लग बफर"</item>
- <item msgid="6699306198357496731">"1M प्रति लग बफर"</item>
- <item msgid="5748528643937500349">"4M प्रति लग बफर"</item>
- <item msgid="1978629051085111592">"16M प्रति लग बफर"</item>
+ <item msgid="6921048829791179331">"निष्क्रिय गर्नुहोस्"</item>
+ <item msgid="2969458029344750262">"६४के प्रति लग बफर"</item>
+ <item msgid="1342285115665698168">"२५६के प्रति लग बफर"</item>
+ <item msgid="1314234299552254621">"१एम प्रति लग बफर"</item>
+ <item msgid="3606047780792894151">"४एम प्रति लग बफर"</item>
+ <item msgid="5431354956856655120">"१६एम प्रति लग बफर"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"सजीविकरण बन्द"</item>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index f859287..5885513 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रीफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रीफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटप पूर्ण जगेडाहरू हाललाई सुरक्षित छैनन्"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन छुनुहोस्"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"असक्षम गरियो"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"सधैं खुल्ला"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"स्वचालित"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView कार्यान्वयन"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView कार्यान्वयन सेट गर्नुहोस्"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"फाइल इन्क्रिप्सनमा रूपान्तरण गर्नुहोस्"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"रुपान्तरण गर्नुहोस्…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"पहिल्यै फाइल इन्क्रिप्ट गरिएको छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index 7f76bba..48b135d 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Uit"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Uit"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K per logbuffer"</item>
- <item msgid="2822309747675758628">"256K per logbuffer"</item>
- <item msgid="6699306198357496731">"1M per logbuffer"</item>
- <item msgid="5748528643937500349">"4M per logbuffer"</item>
- <item msgid="1978629051085111592">"16M per logbuffer"</item>
+ <item msgid="6921048829791179331">"Uit"</item>
+ <item msgid="2969458029344750262">"64 K per logbuffer"</item>
+ <item msgid="1342285115665698168">"256 K per logbuffer"</item>
+ <item msgid="1314234299552254621">"1 M per logbuffer"</item>
+ <item msgid="3606047780792894151">"4 M per logbuffer"</item>
+ <item msgid="5431354956856655120">"16 M per logbuffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatie uit"</item>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 49242f9..1dd477d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hierdoor komt een app in aanmerking om te worden geschreven naar externe opslag, ongeacht de manifestwaarden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Hiermee wordt het formaat van alle activiteiten aanpasbaar gemaakt, ongeacht de manifestwaarden."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Schakelt ondersteuning in voor vensters met experimentele vrije vorm."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Wachtwoord desktopback-up"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak dit aan om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Uitgeschakeld"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Altijd aan"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatisch"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementatie"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView-implementatie instellen"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converteren naar versleuteling op basis van bestanden"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converteren…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Al versleuteld op basis van bestanden"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
index fa624a0..d644da6 100644
--- a/packages/SettingsLib/res/values-pa-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ਹਮੇਸਾਂ HDCP ਜਾਂਚ ਵਰਤੋ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ਬੰਦ"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ਬੰਦ"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="2822309747675758628">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="6699306198357496731">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="5748528643937500349">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
- <item msgid="1978629051085111592">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="6921048829791179331">"ਬੰਦ"</item>
+ <item msgid="2969458029344750262">"64K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="1342285115665698168">"256K ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="1314234299552254621">"1M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="3606047780792894151">"4M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
+ <item msgid="5431354956856655120">"16M ਪ੍ਰਤੀ ਲੌਗ ਬਫਰ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ਐਨੀਮੇਸ਼ਨ ਬੰਦ"</item>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index cbe196c..85f9ffb 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਮੁੜ-ਆਕਾਰ ਵਿੱਚ ਲਿਆਉਂਦੀ ਹੈ, ਚਾਹੇ ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ਼ ਕੁਝ ਵੀ ਹੋਣ।"</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"ਡੈਸਕਟੌਪ ਬੈਕਅਪ ਪਾਸਵਰਡ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਲਈ ਪਾਸਵਰਡ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਛੋਹਵੋ"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ਅਸਮਰੱਥ ਬਣਾਇਆ"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ਹਮੇਸ਼ਾ ਚਾਲੂ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ਆਟੋਮੈਟਿਕ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ਅਮਲ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ਅਮਲ ਸੈੱਟ ਕਰੋ"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ਫ਼ਾਈਲ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕਰੋ"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
index 8df26cd..3b3e95d 100644
--- a/packages/SettingsLib/res/values-pl/arrays.xml
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Zawsze używaj sprawdzania HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Wył."</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Wył."</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 KB/bufor dziennika"</item>
- <item msgid="2822309747675758628">"256 KB/bufor dziennika"</item>
- <item msgid="6699306198357496731">"1 MB/bufor dziennika"</item>
- <item msgid="5748528643937500349">"4 MB/bufor dziennika"</item>
- <item msgid="1978629051085111592">"16 MB/bufor dziennika"</item>
+ <item msgid="6921048829791179331">"Wył."</item>
+ <item msgid="2969458029344750262">"64 KB/bufor dziennika"</item>
+ <item msgid="1342285115665698168">"256 KB/bufor dziennika"</item>
+ <item msgid="1314234299552254621">"1 MB/bufor dziennika"</item>
+ <item msgid="3606047780792894151">"4 MB/bufor dziennika"</item>
+ <item msgid="5431354956856655120">"16 MB/bufor dziennika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacja wyłączona"</item>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 2efb5c9..9f7c022 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Pozwala na zapis aplikacji w pamięci zewn. niezależnie od wartości w pliku manifestu"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Umożliwia zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Włącz dowolny rozmiar okien"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Włącza obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Hasło kopii zapasowej"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Wybierz, aby zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze stacjonarnym."</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Wyłączone"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Zawsze włączone"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatycznie"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementacja WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ustaw implementację WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Przekształć na szyfrowanie plików"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Przekształć…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Pliki są już zaszyfrowane"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
index d8be251..0d94a6d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/buffer de log"</item>
- <item msgid="2822309747675758628">"256K/buffer de log"</item>
- <item msgid="6699306198357496731">"1M/buffer de log"</item>
- <item msgid="5748528643937500349">"4M/buffer de log"</item>
- <item msgid="1978629051085111592">"16M/buffer de log"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+ <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+ <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+ <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+ <item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 28017a9..dd4b58d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index 693430c..6e84fcec 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizar sempre a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Mem. int. 64K p rg."</item>
- <item msgid="2822309747675758628">"Mem. int. 256K p rg"</item>
- <item msgid="6699306198357496731">"Mem. int. 1M p reg."</item>
- <item msgid="5748528643937500349">"Mem. int. 4M p reg."</item>
- <item msgid="1978629051085111592">"Mem. int. 16M p. rg"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K por buffer de registo"</item>
+ <item msgid="1342285115665698168">"256 K por buffer de registo"</item>
+ <item msgid="1314234299552254621">"1 M por buffer de registo"</item>
+ <item msgid="3606047780792894151">"4 M por buffer de registo"</item>
+ <item msgid="5431354956856655120">"16 M por buffer de registo"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desativada"</item>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 2a8402e..0cbe5e4 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualquer aplic. pode ser gravada no arm. ext., independ. dos valores do manif."</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Palavra-passe cópia do comp."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativado"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativado"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Definir implementação WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para a encriptação de ficheiros"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Os ficheiros já estão encriptados"</string>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
index d8be251..0d94a6d 100644
--- a/packages/SettingsLib/res/values-pt/arrays.xml
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sempre usar a verificação HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Desativado"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Desativado"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/buffer de log"</item>
- <item msgid="2822309747675758628">"256K/buffer de log"</item>
- <item msgid="6699306198357496731">"1M/buffer de log"</item>
- <item msgid="5748528643937500349">"4M/buffer de log"</item>
- <item msgid="1978629051085111592">"16M/buffer de log"</item>
+ <item msgid="6921048829791179331">"Desativado"</item>
+ <item msgid="2969458029344750262">"64 K/buffer de log"</item>
+ <item msgid="1342285115665698168">"256 K/buffer de log"</item>
+ <item msgid="1314234299552254621">"1 M/buffer de log"</item>
+ <item msgid="3606047780792894151">"4 M/buffer de log"</item>
+ <item msgid="5431354956856655120">"16 M/buffer de log"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animação desligada"</item>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 28017a9..dd4b58d 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Desativada"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Sempre ativada"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automático"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementação do WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Configurar implementação do WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Converter para criptografia de arquivos"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Converter..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Já criptografado com base em arquivos"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index f75154f..141f877 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Utilizează întotdeauna verificarea HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Dezactivată"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Dezactivată"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/tampon jurnal"</item>
- <item msgid="2822309747675758628">"256K/tampon jurnal"</item>
- <item msgid="6699306198357496731">"1M/tampon jurnal"</item>
- <item msgid="5748528643937500349">"4M/tampon jurnal"</item>
- <item msgid="1978629051085111592">"16M/tampon jurnal"</item>
+ <item msgid="6921048829791179331">"Dezactivată"</item>
+ <item msgid="2969458029344750262">"64 KB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="1342285115665698168">"256 KB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="1314234299552254621">"1 MB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="3606047780792894151">"4 MB/zonă-tampon de înregistrări în jurnal"</item>
+ <item msgid="5431354956856655120">"16 MB/zonă-tampon de înregistrări în jurnal"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animație dezactivată"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index c45ede5..a666da0 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Atingeţi pentru a modifica sau pentru a elimina parola pentru copiile de rezervă complete pe desktop"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Dezactivată"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Activată permanent"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automat"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementare WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Setați implementarea WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Faceți conversia la criptarea bazată pe sistemul de fișiere"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertiți…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Criptarea bazată pe sistemul de fișiere este finalizată"</string>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
index c8c789e..78965ac 100644
--- a/packages/SettingsLib/res/values-ru/arrays.xml
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Всегда использовать проверку HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 КБ"</item>
- <item msgid="505611754508988476">"256 КБ"</item>
- <item msgid="6361286924268716397">"1 МБ"</item>
- <item msgid="6405203239560695266">"4 МБ"</item>
- <item msgid="3025431211013424097">"16 МБ"</item>
+ <item msgid="8665206199209698501">"Выкл."</item>
+ <item msgid="1593289376502312923">"64 КБ"</item>
+ <item msgid="487545340236145324">"256 КБ"</item>
+ <item msgid="2423528675294333831">"1 МБ"</item>
+ <item msgid="180883774509476541">"4 МБ"</item>
+ <item msgid="2803199102589126938">"16 МБ"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 КБ"</item>
- <item msgid="3534782711045262344">"256 КБ"</item>
- <item msgid="8085867209202153403">"1 МБ"</item>
+ <item msgid="6089470720451068364">"Выкл."</item>
+ <item msgid="4622460333038586791">"64 КБ"</item>
+ <item msgid="2212125625169582330">"256 КБ"</item>
+ <item msgid="1704946766699242653">"1 МБ"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Буфер: макс. 64 КБ"</item>
- <item msgid="2822309747675758628">"Буфер: макс. 256 КБ"</item>
- <item msgid="6699306198357496731">"Буфер: макс. 1 МБ"</item>
- <item msgid="5748528643937500349">"Буфер: макс. 4 МБ"</item>
- <item msgid="1978629051085111592">"Буфер: макс. 16 МБ"</item>
+ <item msgid="6921048829791179331">"Выкл."</item>
+ <item msgid="2969458029344750262">"Буфер: макс. 64 КБ"</item>
+ <item msgid="1342285115665698168">"Буфер: макс. 256 КБ"</item>
+ <item msgid="1314234299552254621">"Буфер: макс. 1 МБ"</item>
+ <item msgid="3606047780792894151">"Буфер: макс. 4 МБ"</item>
+ <item msgid="5431354956856655120">"Буфер: макс. 16 МБ"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Без анимации"</item>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 3c30b26..e93bae1 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Изменить или удалить пароль для резервного копирования"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Отключено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Всегда включено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматическое переключение"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Сервис WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Настройки сервиса WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Переход к шифрованию файлов"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Перейти…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Шифрование файлов уже включено"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/arrays.xml b/packages/SettingsLib/res/values-si-rLK/arrays.xml
index 564ecee..ab30e45 100644
--- a/packages/SettingsLib/res/values-si-rLK/arrays.xml
+++ b/packages/SettingsLib/res/values-si-rLK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"සැමවිටම HDCP පිරික්සුම භාවිතා කරන්න"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ක්රියාවිරහිතය"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ක්රියාවිරහිතය"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"ලොග අන්තරාවකට 64K"</item>
- <item msgid="2822309747675758628">"ලොග අන්තරාවකට 256K"</item>
- <item msgid="6699306198357496731">"ලොග අන්තරාවකට 1M"</item>
- <item msgid="5748528643937500349">"ලොග අන්තරාවකට 4M"</item>
- <item msgid="1978629051085111592">"ලොග අන්තරාවකට 16M"</item>
+ <item msgid="6921048829791179331">"ක්රියාවිරහිතය"</item>
+ <item msgid="2969458029344750262">"ලොග අන්තරාවකට 64K"</item>
+ <item msgid="1342285115665698168">"ලොග අන්තරාවකට 256K"</item>
+ <item msgid="1314234299552254621">"ලොග අන්තරාවකට 1M"</item>
+ <item msgid="3606047780792894151">"ලොග අන්තරාවකට 4M"</item>
+ <item msgid="5431354956856655120">"ලොග අන්තරාවකට 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"සජිවිකරණය අක්රිය කිරීම"</item>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index 1ffd840..6753624 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"ක්රියාකාරකම් ප්රතිප්රමාණ කළ හැකි බවට බල කරන්න"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්රියාකාරකම් බහු-කවුළු සඳහා ප්රතිප්රමාණ කළ හැකි බවට පත් කරයි."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට ස්පර්ශ කරන්න"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"අබලයි"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"සැමවිට ක්රියාත්මක"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"ස්වයංක්රීය"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ක්රියාත්මක කිරීම"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ක්රියාත්මක කිරීම සකසන්න"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ගොනු සංකේතනයට පරිවර්තනය කරන්න"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"පරිවර්තනය කරන්න..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"දැනටමත් ගොනුව සංකේතනය කර ඇත"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index ec33e63..9a56e78 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vždy používať kontrolu HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Vypnuté"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Vypnuté"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB na vyrovn. pamäť denníka"</item>
- <item msgid="2822309747675758628">"256 kB na vyrovn. pamäť denníka"</item>
- <item msgid="6699306198357496731">"1 MB na vyrovn. pamäť denníka"</item>
- <item msgid="5748528643937500349">"4 MB na vyrovn. pamäť denníka"</item>
- <item msgid="1978629051085111592">"16 MB na vyrovn. pamäť denníka"</item>
+ <item msgid="6921048829791179331">"Vypnuté"</item>
+ <item msgid="2969458029344750262">"64 kB na vyrov. pamäť denníka"</item>
+ <item msgid="1342285115665698168">"256 kB na vyrov. pamäť denníka"</item>
+ <item msgid="1314234299552254621">"1 MB na vyrov. pam. denníka"</item>
+ <item msgid="3606047780792894151">"4 MB na vyrov. pamäť denníka"</item>
+ <item msgid="5431354956856655120">"16 MB na vyrov. pamäť denníka"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animácia je vypnutá"</item>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 9b851b9..7db7835 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotykom zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Vypnuté"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vždy zapnuté"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatický"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementácia komponenta WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavenie implementácie komponenta WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertovať na šifrovanie súborov"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertovať…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Súbory sú už šifrované"</string>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
index 253f113..11b2bab 100644
--- a/packages/SettingsLib/res/values-sl/arrays.xml
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Vedno uporabi preverjanje HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Izklopljeno"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Izklopljeno"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K/medpom. dnevn."</item>
- <item msgid="2822309747675758628">"256 K/medpom. dnev."</item>
- <item msgid="6699306198357496731">"1 M/medpom. dnevn."</item>
- <item msgid="5748528643937500349">"4 M/medpom. dnevn."</item>
- <item msgid="1978629051085111592">"16 M/medpom. dnevn."</item>
+ <item msgid="6921048829791179331">"Izklopljeno"</item>
+ <item msgid="2969458029344750262">"64 K/medpomnilnik dnevnika"</item>
+ <item msgid="1342285115665698168">"256 K/medpomnilnik dnevnika"</item>
+ <item msgid="1314234299552254621">"1 M/medpomnilnik dnevnika"</item>
+ <item msgid="3606047780792894151">"4 M/medpomnilnik dnevnika"</item>
+ <item msgid="5431354956856655120">"16 M/medpomnilnik dnevnika"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacija je izključena"</item>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 04918e0..ed37933 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Onemogočeno"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Vedno vklopljeno"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Samodejno"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Izvedba spletnega pogleda"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Nastavitev izvedbe spletnega pogleda"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Preklop na šifriranje podatkov"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Preklop …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Šifriranje podatkov je že uveljavljeno"</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/arrays.xml b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
index 7473f16..0f0efb8 100644
--- a/packages/SettingsLib/res/values-sq-rAL/arrays.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Përdor gjithmonë kontrollin e HDCP-së"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"Joaktiv"</item>
+ <item msgid="1593289376502312923">"64 mijë"</item>
+ <item msgid="487545340236145324">"256 mijë"</item>
+ <item msgid="2423528675294333831">"1 milion"</item>
+ <item msgid="180883774509476541">"4 milionë"</item>
+ <item msgid="2803199102589126938">"16 milionë"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"Joaktiv"</item>
+ <item msgid="4622460333038586791">"64 mijë"</item>
+ <item msgid="2212125625169582330">"256 mijë"</item>
+ <item msgid="1704946766699242653">"1 milion"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 mijë / memorie regjistrimi"</item>
- <item msgid="2822309747675758628">"256K për çdo memorie të përkohshme"</item>
- <item msgid="6699306198357496731">"1 M për memorien e regjistrit"</item>
- <item msgid="5748528643937500349">"4 M për memorien e regjistrit"</item>
- <item msgid="1978629051085111592">"16 M për memorien e regjistrit"</item>
+ <item msgid="6921048829791179331">"Joaktiv"</item>
+ <item msgid="2969458029344750262">"64 mijë/memorie regjistrimi"</item>
+ <item msgid="1342285115665698168">"256 mijë/memorie regjistrimi"</item>
+ <item msgid="1314234299552254621">"1 milion/memorie regjistrimi"</item>
+ <item msgid="3606047780792894151">"4 milionë/memorie regjistrimi"</item>
+ <item msgid="5431354956856655120">"16 milionë/memorie regjistrimi"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animacioni është i çaktivizuar"</item>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index 3bc769c..7f4d6a8 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bën që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivizo dritaret me formë të lirë"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Prek për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Çaktivizuar"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Gjithmonë aktive"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatike"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Zbatimi i WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Cakto zbatimin e WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konverto në enkriptimin e skedarit"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konverto..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Enkriptimi i skedarit është kryer tashmë"</string>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
index cd44e15..2389339 100644
--- a/packages/SettingsLib/res/values-sr/arrays.xml
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Увек користи HDCP проверу"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Искључено"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Искључено"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB по баферу евиденције"</item>
- <item msgid="2822309747675758628">"256 kB по баферу евиденције"</item>
- <item msgid="6699306198357496731">"1 MB по баферу евиденције"</item>
- <item msgid="5748528643937500349">"4 MB по баферу евиденције"</item>
- <item msgid="1978629051085111592">"16 MB по баферу евиденције"</item>
+ <item msgid="6921048829791179331">"Искључено"</item>
+ <item msgid="2969458029344750262">"64 kB по међумеморији евиденције"</item>
+ <item msgid="1342285115665698168">"256 kB по међумеморији евиденције"</item>
+ <item msgid="1314234299552254621">"1 MB по међумеморији евиденције"</item>
+ <item msgid="3606047780792894151">"4 MB по међумеморији евиденције"</item>
+ <item msgid="5431354956856655120">"16 MB по међумеморији евиденције"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анимација је искључена"</item>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 036622f..9596ce5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Онемогућено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Увек укључено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Аутоматски"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
index 54537f4..cbc7dde 100644
--- a/packages/SettingsLib/res/values-sv/arrays.xml
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Använd alltid HDCP-kontroll"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 kB"</item>
- <item msgid="505611754508988476">"256 kB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Av"</item>
+ <item msgid="1593289376502312923">"64 kB"</item>
+ <item msgid="487545340236145324">"256 kB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 kB"</item>
- <item msgid="3534782711045262344">"256 kB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Av"</item>
+ <item msgid="4622460333038586791">"64 kB"</item>
+ <item msgid="2212125625169582330">"256 kB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 kB/loggbuffert"</item>
- <item msgid="2822309747675758628">"256 kB/loggbuffert"</item>
- <item msgid="6699306198357496731">"1 MB/loggbuffert"</item>
- <item msgid="5748528643937500349">"4 MB/loggbuffert"</item>
- <item msgid="1978629051085111592">"16 MB/loggbuffert"</item>
+ <item msgid="6921048829791179331">"Av"</item>
+ <item msgid="2969458029344750262">"64 kB/loggbuffert"</item>
+ <item msgid="1342285115665698168">"256 kB/loggbuffert"</item>
+ <item msgid="1314234299552254621">"1 MB/loggbuffert"</item>
+ <item msgid="3606047780792894151">"4 MB/loggbuffert"</item>
+ <item msgid="5431354956856655120">"16 MB/loggbuffert"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animering avstängd"</item>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 2f95b06..7d0d0a0 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Detta gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Inaktiverad"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Alltid på"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Automatiskt"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView-implementering"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Ange WebView-implementering"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertera till filkryptering"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertera …"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Filkryptering används redan"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 450e385..8593fd5 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Kila wakati tumia ukakuaji wa HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"K64"</item>
- <item msgid="505611754508988476">"K256"</item>
- <item msgid="6361286924268716397">"M1"</item>
- <item msgid="6405203239560695266">"M4"</item>
- <item msgid="3025431211013424097">"M16"</item>
+ <item msgid="8665206199209698501">"Imezimwa"</item>
+ <item msgid="1593289376502312923">"K64"</item>
+ <item msgid="487545340236145324">"K256"</item>
+ <item msgid="2423528675294333831">"M1"</item>
+ <item msgid="180883774509476541">"M4"</item>
+ <item msgid="2803199102589126938">"M16"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"K64"</item>
- <item msgid="3534782711045262344">"K256"</item>
- <item msgid="8085867209202153403">"M1"</item>
+ <item msgid="6089470720451068364">"Imezimwa"</item>
+ <item msgid="4622460333038586791">"K64"</item>
+ <item msgid="2212125625169582330">"K256"</item>
+ <item msgid="1704946766699242653">"M1"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"K64 kwa kumbukumbu"</item>
- <item msgid="2822309747675758628">"K256 kwa kumbukumbu"</item>
- <item msgid="6699306198357496731">"M1 kwa kumbukumbu"</item>
- <item msgid="5748528643937500349">"M4 kwa kumbukumbu"</item>
- <item msgid="1978629051085111592">"M16 kwa kumbukumbu"</item>
+ <item msgid="6921048829791179331">"Imezimwa"</item>
+ <item msgid="2969458029344750262">"K64 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="1342285115665698168">"K256 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="1314234299552254621">"M1 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="3606047780792894151">"M4 kwa kila akiba ya kumbukumbu"</item>
+ <item msgid="5431354956856655120">"M16 kwa kila akiba ya kumbukumbu"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Haiwani imezimwa"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index c4adcc9..d1041da 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Imezimwa"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Imewashwa kila wakati"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatiki"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Utekelezaji wa WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Weka utekelezaji wa WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Badilisha kuwa usimbaji fiche wa faili"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Badilisha..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Tayari faili imesimbwa kwa njia fiche"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/arrays.xml b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
index ad42159..18deff3 100644
--- a/packages/SettingsLib/res/values-ta-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP சரிபார்ப்பை எப்போதும் பயன்படுத்து"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"முடக்கு"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"முடக்கு"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K / லாக் பஃபர்"</item>
- <item msgid="2822309747675758628">"256K / லாக் பஃபர்"</item>
- <item msgid="6699306198357496731">"1M / லாக் பஃபர்"</item>
- <item msgid="5748528643937500349">"4M / லாக் பஃபர்"</item>
- <item msgid="1978629051085111592">"16M / லாக் பஃபர்"</item>
+ <item msgid="6921048829791179331">"முடக்கத்தில்"</item>
+ <item msgid="2969458029344750262">"64K / லாக் பஃபர்"</item>
+ <item msgid="1342285115665698168">"256K / லாக் பஃபர்"</item>
+ <item msgid="1314234299552254621">"1M / லாக் பஃபர்"</item>
+ <item msgid="3606047780792894151">"4M / லாக் பஃபர்"</item>
+ <item msgid="5431354956856655120">"16M / லாக் பஃபர்"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"அனிமேஷனை முடக்கு"</item>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index f4fee1f..e66f073 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"டெஸ்க்டாப்பின் முழுமையான காப்புப்பிரதிகளுக்கான கடவுச்சொல்லை மாற்றுவதற்கு அல்லது அகற்றுவதற்குத் தொடவும்"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"முடக்கப்பட்டது"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"எப்போதும் இயக்கத்தில் வை"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"தானியங்கு"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView செயல்படுத்தல்"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView செயல்படுத்தலை அமை"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"கோப்பு முறைமையாக்கத்திற்கு மாற்று"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"மாற்று…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ஏற்கனவே கோப்பு முறைமையாக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/arrays.xml b/packages/SettingsLib/res/values-te-rIN/arrays.xml
index 9287aba..3ba0dc7 100644
--- a/packages/SettingsLib/res/values-te-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-te-rIN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ఎప్పటికీ HDCP తనిఖీని ఉపయోగించు"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"ఆఫ్"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"ఆఫ్"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"లాగ్ బఫర్కి 64K"</item>
- <item msgid="2822309747675758628">"లాగ్ బఫర్కి 256K"</item>
- <item msgid="6699306198357496731">"లాగ్ బఫర్కి 1M"</item>
- <item msgid="5748528643937500349">"లాగ్ బఫర్కి 4M"</item>
- <item msgid="1978629051085111592">"లాగ్ బఫర్కి 16M"</item>
+ <item msgid="6921048829791179331">"ఆఫ్ చేయబడింది"</item>
+ <item msgid="2969458029344750262">"లాగ్ బఫర్కి 64K"</item>
+ <item msgid="1342285115665698168">"లాగ్ బఫర్కి 256K"</item>
+ <item msgid="1314234299552254621">"లాగ్ బఫర్కి 1M"</item>
+ <item msgid="3606047780792894151">"లాగ్ బఫర్కి 4M"</item>
+ <item msgid="5431354956856655120">"లాగ్ బఫర్కి 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"యానిమేషన్ ఆఫ్లో ఉంది"</item>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index ce7fbf2..80b84f0 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను బహుళ విండోల్లో సరిపోయేటట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"డెస్క్టాప్ బ్యాకప్ పాస్వర్డ్"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"డెస్క్టాప్ పూర్తి బ్యాకప్లు ప్రస్తుతం రక్షించబడలేదు"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"డెస్క్టాప్ పూర్తి బ్యాకప్ల కోసం పాస్వర్డ్ను మార్చడానికి లేదా తీసివేయడానికి తాకండి"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"నిలిపివేయబడింది"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ఎల్లప్పుడూ ఆన్లో ఉంచు"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"స్వయంచాలకం"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"వెబ్ వీక్షణ అమలు"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"వెబ్ వీక్షణ అమలుని సెట్ చేయండి"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"ఫైల్ గుప్తీకరణకు మార్చు"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"మార్చండి…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ఫైల్ ఇప్పటికే గుప్తీకరించబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
index 43d2739..4282975 100644
--- a/packages/SettingsLib/res/values-th/arrays.xml
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ใช้การตรวจสอบ HDCP เสมอ"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 K"</item>
- <item msgid="505611754508988476">"256 K"</item>
- <item msgid="6361286924268716397">"1 M"</item>
- <item msgid="6405203239560695266">"4 M"</item>
- <item msgid="3025431211013424097">"16 M"</item>
+ <item msgid="8665206199209698501">"ปิด"</item>
+ <item msgid="1593289376502312923">"64 K"</item>
+ <item msgid="487545340236145324">"256 K"</item>
+ <item msgid="2423528675294333831">"1 M"</item>
+ <item msgid="180883774509476541">"4 M"</item>
+ <item msgid="2803199102589126938">"16 M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 K"</item>
- <item msgid="3534782711045262344">"256 K"</item>
- <item msgid="8085867209202153403">"1 M"</item>
+ <item msgid="6089470720451068364">"ปิด"</item>
+ <item msgid="4622460333038586791">"64 K"</item>
+ <item msgid="2212125625169582330">"256 K"</item>
+ <item msgid="1704946766699242653">"1 M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="2822309747675758628">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="6699306198357496731">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="5748528643937500349">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
- <item msgid="1978629051085111592">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="6921048829791179331">"ปิด"</item>
+ <item msgid="2969458029344750262">"64 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="1342285115665698168">"256 K ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="1314234299552254621">"1 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="3606047780792894151">"4 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
+ <item msgid="5431354956856655120">"16 M ต่อบัฟเฟอร์ไฟล์บันทึก"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"ปิดภาพเคลื่อนไหว"</item>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index c91bb42..6826419 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"แตะเพื่อเปลี่ยนหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"ปิดใช้แล้ว"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"เปิดใช้เสมอ"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"อัตโนมัติ"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"การใช้งาน WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"ตั้งค่าการใช้งาน WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"แปลงเป็นการเข้ารหัสไฟล์"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"แปลง…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"เข้ารหัสไฟล์แล้ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
index c7cf6d2..a7fb68c 100644
--- a/packages/SettingsLib/res/values-tl/arrays.xml
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Palaging gumamit ng pagsusuring HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"I-off"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"I-off"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K kada log buffer"</item>
- <item msgid="2822309747675758628">"256K kada log buffer"</item>
- <item msgid="6699306198357496731">"1M kada log buffer"</item>
- <item msgid="5748528643937500349">"4M kada log buffer"</item>
- <item msgid="1978629051085111592">"16M kada log buffer"</item>
+ <item msgid="6921048829791179331">"I-off"</item>
+ <item msgid="2969458029344750262">"64K kada log buffer"</item>
+ <item msgid="1342285115665698168">"256K kada log buffer"</item>
+ <item msgid="1314234299552254621">"1M kada log buffer"</item>
+ <item msgid="3606047780792894151">"4M kada log buffer"</item>
+ <item msgid="5431354956856655120">"16M kada log buffer"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Naka-off ang animation"</item>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index a389feb..8f62326 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pindutin upang baguhin o alisin ang password para sa mga buong pag-backup ng desktop"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Naka-disable"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Palaging naka-on"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Awtomatiko"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Pagpapatupad sa WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Itakda ang pagpapatupad sa WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"I-convert at gawing pag-encrypt ng file"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"I-convert..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Na-encrypt na ang file"</string>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
index 9326903e..0bae437 100644
--- a/packages/SettingsLib/res/values-tr/arrays.xml
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"HDCP denetimini her zaman kullan"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"Kapalı"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"Kapalı"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Günlük arabelleği başına 64 KB"</item>
- <item msgid="2822309747675758628">"Günlük arabelleği başına 256 KB"</item>
- <item msgid="6699306198357496731">"Günlük arabelleği başına 1 MB"</item>
- <item msgid="5748528643937500349">"Günlük arabelleği başına 4 MB"</item>
- <item msgid="1978629051085111592">"Günlük arabelleği başına 16 MB"</item>
+ <item msgid="6921048829791179331">"Kapalı"</item>
+ <item msgid="2969458029344750262">"Günlük arabelleği başına 64 KB"</item>
+ <item msgid="1342285115665698168">"Günlük arabelleği başına 256 KB"</item>
+ <item msgid="1314234299552254621">"Günlük arabelleği başına 1 MB"</item>
+ <item msgid="3606047780792894151">"Günlük arabelleği başına 4 MB"</item>
+ <item msgid="5431354956856655120">"Günlük arabelleği başına 16 MB"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animasyon kapalı"</item>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 48ed867..5e0839a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Devre dışı"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Her zaman açık"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Otomatik"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView kullanımı"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView kullanımını ayarla"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Dosya şifrelemeye dönüştür"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Dönüştür…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Dosya şifreleme zaten uygulandı"</string>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
index 6cccc8c..0786ac3 100644
--- a/packages/SettingsLib/res/values-uk/arrays.xml
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Завжди використовувати перевірку HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 Кб"</item>
- <item msgid="505611754508988476">"256 Кб"</item>
- <item msgid="6361286924268716397">"1 Мб"</item>
- <item msgid="6405203239560695266">"4 Мб"</item>
- <item msgid="3025431211013424097">"16 Мб"</item>
+ <item msgid="8665206199209698501">"Вимкнено"</item>
+ <item msgid="1593289376502312923">"64 Кб"</item>
+ <item msgid="487545340236145324">"256 Кб"</item>
+ <item msgid="2423528675294333831">"1 Мб"</item>
+ <item msgid="180883774509476541">"4 Мб"</item>
+ <item msgid="2803199102589126938">"16 Мб"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 Кб"</item>
- <item msgid="3534782711045262344">"256 Кб"</item>
- <item msgid="8085867209202153403">"1 Мб"</item>
+ <item msgid="6089470720451068364">"Вимкнено"</item>
+ <item msgid="4622460333038586791">"64 Кб"</item>
+ <item msgid="2212125625169582330">"256 Кб"</item>
+ <item msgid="1704946766699242653">"1 Мб"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Буфер: макс. 64 Кб"</item>
- <item msgid="2822309747675758628">"Буфер: макс. 256 Кб"</item>
- <item msgid="6699306198357496731">"Буфер: макс. 1 Мб"</item>
- <item msgid="5748528643937500349">"Буфер: макс. 4 Мб"</item>
- <item msgid="1978629051085111592">"Буфер: макс. 16 Мб"</item>
+ <item msgid="6921048829791179331">"Вимкнено"</item>
+ <item msgid="2969458029344750262">"Буфер журналу: 64 Кб"</item>
+ <item msgid="1342285115665698168">"Буфер журналу: 256 Кб"</item>
+ <item msgid="1314234299552254621">"Буфер журналу: 1 Мб"</item>
+ <item msgid="3606047780792894151">"Буфер журналу: 4 Мб"</item>
+ <item msgid="5431354956856655120">"Буфер журналу: 16 Мб"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Анімацію вимкнено"</item>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 5a0ddd0..2448b23 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Активність масштабуватиметься на кілька вікон, незалежно від значень у файлі маніфесту."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Пароль резерв.копії на ПК"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Повні резервні копії на комп’ютері наразі не захищені"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Торкніться, щоб змінити чи видалити пароль для повного резервного копіювання на комп’ютер"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Вимкнено"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Завжди ввімкнено"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Автоматично"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Застосування WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Налаштувати застосування WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертувати в зашифрований файл"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертація…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Уже конвертовано в зашифрований файл"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/arrays.xml b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
index 80fb750..e1fe269 100644
--- a/packages/SettingsLib/res/values-ur-rPK/arrays.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"ہمیشہ HDCP چیکنگ استعمال کریں"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"آف"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"آف"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K فی لاگ بفر"</item>
- <item msgid="2822309747675758628">"256K فی لاگ بفر"</item>
- <item msgid="6699306198357496731">"1M فی لاگ بفر"</item>
- <item msgid="5748528643937500349">"4M فی لاگ بفر"</item>
- <item msgid="1978629051085111592">"16M فی لاگ بفر"</item>
+ <item msgid="6921048829791179331">"آف"</item>
+ <item msgid="2969458029344750262">"64K فی لاگ بفر"</item>
+ <item msgid="1342285115665698168">"256K فی لاگ بفر"</item>
+ <item msgid="1314234299552254621">"1M فی لاگ بفر"</item>
+ <item msgid="3606047780792894151">"4M فی لاگ بفر"</item>
+ <item msgid="5431354956856655120">"16M فی لاگ بفر"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"اینیمیشن آف ہے"</item>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 3f6563b..0834303 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے ٹچ کریں"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"غیر فعال"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"ہمیشہ آن"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"خودکار"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView کا نفاذ"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView کا نفاذ سیٹ کریں"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"فائل مرموز کاری میں بدلیں"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"بدلیں…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"فائل پہلے ہی مرموز شدہ ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
index a84c5d5..53d4db7 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Har doim HDCP tekshiruvidan foydalanilsin"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64 KB"</item>
- <item msgid="505611754508988476">"256 KB"</item>
- <item msgid="6361286924268716397">"1 MB"</item>
- <item msgid="6405203239560695266">"4 MB"</item>
- <item msgid="3025431211013424097">"16 MB"</item>
+ <item msgid="8665206199209698501">"O‘chiq"</item>
+ <item msgid="1593289376502312923">"64 KB"</item>
+ <item msgid="487545340236145324">"256 KB"</item>
+ <item msgid="2423528675294333831">"1 MB"</item>
+ <item msgid="180883774509476541">"4 MB"</item>
+ <item msgid="2803199102589126938">"16 MB"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64 KB"</item>
- <item msgid="3534782711045262344">"256 KB"</item>
- <item msgid="8085867209202153403">"1 MB"</item>
+ <item msgid="6089470720451068364">"O‘chiq"</item>
+ <item msgid="4622460333038586791">"64 KB"</item>
+ <item msgid="2212125625169582330">"256 KB"</item>
+ <item msgid="1704946766699242653">"1 MB"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"Bufer: maks. 64 KB"</item>
- <item msgid="2822309747675758628">"Bufer: maks. 256 KB"</item>
- <item msgid="6699306198357496731">"Bufer: maks. 1 MB"</item>
- <item msgid="5748528643937500349">"Bufer: maks. 4 MB"</item>
- <item msgid="1978629051085111592">"Bufer: maks. 16 MB"</item>
+ <item msgid="6921048829791179331">"O‘chiq"</item>
+ <item msgid="2969458029344750262">"Bufer: maks. 64 KB"</item>
+ <item msgid="1342285115665698168">"Bufer: maks. 256 KB"</item>
+ <item msgid="1314234299552254621">"Bufer: maks. 1 MB"</item>
+ <item msgid="3606047780792894151">"Bufer: maks. 4 MB"</item>
+ <item msgid="5431354956856655120">"Bufer: maks. 16 MB"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Animatsiya o‘chiq"</item>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index 1033bb19..d2d8b76 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ish stoli to\'liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing."</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"O‘chiq"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Har doim yoniq tursin"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Avtomatik"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView ta’minotchisi"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView ta’minotchisini sozlash"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Faylli shifrga o‘girish"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"O‘girish…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Fayl allaqachon shifrlangan"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index 7c3181f..b03d847 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Luôn sử dụng kiểm tra HDCP"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Tắt"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Tắt"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K/lần tải nhật ký"</item>
- <item msgid="2822309747675758628">"256K/lần tải nhật ký"</item>
- <item msgid="6699306198357496731">"1M/lần tải nhật ký"</item>
- <item msgid="5748528643937500349">"4M/lần tải nhật ký"</item>
- <item msgid="1978629051085111592">"16M/lần tải nhật ký"</item>
+ <item msgid="6921048829791179331">"Tắt"</item>
+ <item msgid="2969458029344750262">"64K/lần tải nhật ký"</item>
+ <item msgid="1342285115665698168">"256K/lần tải nhật ký"</item>
+ <item msgid="1314234299552254621">"1M/lần tải nhật ký"</item>
+ <item msgid="3606047780792894151">"4M/lần tải nhật ký"</item>
+ <item msgid="5431354956856655120">"16M/lần tải nhật ký"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Tắt hình động"</item>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index e73f925..178e301 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Chạm để thay đổi hoặc xóa mật khẩu dành cho bộ sao lưu toàn bộ tới máy tính"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Đã tắt"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Luôn bật"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Tự động"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Triển khai WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Đặt triển khai WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Chuyển đổi sang mã hóa tệp"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Chuyển đổi..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Đã mã hóa tệp"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
index 1378aaa..d1d8937 100644
--- a/packages/SettingsLib/res/values-zh-rCN/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"始终使用 HDCP 检查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"关闭"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"关闭"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"每个日志缓冲区64K"</item>
- <item msgid="2822309747675758628">"每个日志缓冲区256K"</item>
- <item msgid="6699306198357496731">"每个日志缓冲区1M"</item>
- <item msgid="5748528643937500349">"每个日志缓冲区4M"</item>
- <item msgid="1978629051085111592">"每个日志缓冲区16M"</item>
+ <item msgid="6921048829791179331">"关闭"</item>
+ <item msgid="2969458029344750262">"每个日志缓冲区 64K"</item>
+ <item msgid="1342285115665698168">"每个日志缓冲区 256K"</item>
+ <item msgid="1314234299552254621">"每个日志缓冲区 1M"</item>
+ <item msgid="3606047780792894151">"每个日志缓冲区 4M"</item>
+ <item msgid="5431354956856655120">"每个日志缓冲区 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"关闭动画"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 886a7ce..5b96383 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"触摸可更改或删除用于桌面完整备份的密码"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"始终开启"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自动"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"转换为文件加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"转换…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"文件已加密"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
index f15caff..a7b0031 100644
--- a/packages/SettingsLib/res/values-zh-rHK/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"永遠使用 HDCP 檢查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"關閉"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"關閉"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"每個記錄緩衝區 64K"</item>
- <item msgid="2822309747675758628">"每個記錄緩衝區 256K"</item>
- <item msgid="6699306198357496731">"每個記錄緩衝區 1M"</item>
- <item msgid="5748528643937500349">"每個記錄緩衝區 4M"</item>
- <item msgid="1978629051085111592">"每個記錄緩衝區 16M"</item>
+ <item msgid="6921048829791179331">"關閉"</item>
+ <item msgid="2969458029344750262">"每個記錄緩衝區 64K"</item>
+ <item msgid="1342285115665698168">"每個記錄緩衝區 256K"</item>
+ <item msgid="1314234299552254621">"每個記錄緩衝區 1M"</item>
+ <item msgid="3606047780792894151">"每個記錄緩衝區 4M"</item>
+ <item msgid="5431354956856655120">"每個記錄緩衝區 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index afbdb31..db5f09b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可更改或移除桌上電腦完整備份的密碼"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"永遠開啟"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 設置"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 設置"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換為檔案加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換…"</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已加密檔案"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
index 50bde80..32a2065 100644
--- a/packages/SettingsLib/res/values-zh-rTW/arrays.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"一律使用 HDCP 檢查"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"關閉"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"關閉"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"每個紀錄緩衝區 64K"</item>
- <item msgid="2822309747675758628">"每個紀錄緩衝區 256K"</item>
- <item msgid="6699306198357496731">"每個紀錄緩衝區 1M"</item>
- <item msgid="5748528643937500349">"每個紀錄緩衝區 4M"</item>
- <item msgid="1978629051085111592">"每個紀錄緩衝區 16M"</item>
+ <item msgid="6921048829791179331">"關閉"</item>
+ <item msgid="2969458029344750262">"每個紀錄緩衝區 64K"</item>
+ <item msgid="1342285115665698168">"每個紀錄緩衝區 256K"</item>
+ <item msgid="1314234299552254621">"每個紀錄緩衝區 1M"</item>
+ <item msgid="3606047780792894151">"每個紀錄緩衝區 4M"</item>
+ <item msgid="5431354956856655120">"每個紀錄緩衝區 16M"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"關閉動畫"</item>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 88109a2..787a442 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -247,6 +247,10 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
+ <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+ <skip />
+ <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+ <skip />
<string name="local_backup_password_title" msgid="3860471654439418822">"電腦備份密碼"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可變更或移除電腦完整備份的密碼"</string>
@@ -273,6 +277,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"已停用"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"一律開啟"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"自動"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 實作"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"設定 WebView 實作"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"轉換成檔案加密"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"轉換..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"已將檔案加密"</string>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
index eaadce6..2bb849f 100644
--- a/packages/SettingsLib/res/values-zu/arrays.xml
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -59,23 +59,26 @@
<item msgid="45075631231212732">"Sebenzisa njalo ukuhlola kwe-HDPC"</item>
</string-array>
<string-array name="select_logd_size_titles">
- <item msgid="3100534874529240291">"64K"</item>
- <item msgid="505611754508988476">"256K"</item>
- <item msgid="6361286924268716397">"1M"</item>
- <item msgid="6405203239560695266">"4M"</item>
- <item msgid="3025431211013424097">"16M"</item>
+ <item msgid="8665206199209698501">"Valiwe"</item>
+ <item msgid="1593289376502312923">"64K"</item>
+ <item msgid="487545340236145324">"256K"</item>
+ <item msgid="2423528675294333831">"1M"</item>
+ <item msgid="180883774509476541">"4M"</item>
+ <item msgid="2803199102589126938">"16M"</item>
</string-array>
<string-array name="select_logd_size_lowram_titles">
- <item msgid="524799395770610154">"64K"</item>
- <item msgid="3534782711045262344">"256K"</item>
- <item msgid="8085867209202153403">"1M"</item>
+ <item msgid="6089470720451068364">"Valiwe"</item>
+ <item msgid="4622460333038586791">"64K"</item>
+ <item msgid="2212125625169582330">"256K"</item>
+ <item msgid="1704946766699242653">"1M"</item>
</string-array>
<string-array name="select_logd_size_summaries">
- <item msgid="7346595473588765019">"64K ngebhafa yelogu ngayinye"</item>
- <item msgid="2822309747675758628">"256K ngebhafa yelogu ngayinye"</item>
- <item msgid="6699306198357496731">"1M ngebhafa yelogu ngayinye"</item>
- <item msgid="5748528643937500349">"4M ngebhafa yelogu ngayinye"</item>
- <item msgid="1978629051085111592">"16M ngebhafa yelogu ngayinye"</item>
+ <item msgid="6921048829791179331">"Valiwe"</item>
+ <item msgid="2969458029344750262">"64K ngebhafa yelogu ngayinye"</item>
+ <item msgid="1342285115665698168">"256K ngebhafa yelogu ngayinye"</item>
+ <item msgid="1314234299552254621">"1M ngebhafa yelogu ngayi"</item>
+ <item msgid="3606047780792894151">"4M ngebhafa yelogu ngayinye"</item>
+ <item msgid="5431354956856655120">"16M ngebhafa yelogu ngayinye"</item>
</string-array>
<string-array name="window_animation_scale_entries">
<item msgid="8134156599370824081">"Isithombe esinyakazayo sivliwe"</item>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 69c3c21..bf3addf 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -247,6 +247,8 @@
<string name="force_allow_on_external_summary" msgid="3191952505860343233">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
<string name="force_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
<string name="force_resizable_activities_summary" msgid="4508217476997182216">"Yenza yonke imisebenzi ibe nosayizi abasha kuwindi lokuningi, ngokunganaki amanani we-manifest."</string>
+ <string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
+ <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
<string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
<string name="local_backup_password_summary_change" msgid="2731163425081172638">"Khetha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
@@ -273,6 +275,8 @@
<string name="night_mode_no" msgid="9171772244775838901">"Kukhutshaziwe"</string>
<string name="night_mode_yes" msgid="2218157265997633432">"Njalo ivuliwe"</string>
<string name="night_mode_auto" msgid="7508348175804304327">"Okuzenzakalelayo"</string>
+ <string name="select_webview_provider_title" msgid="4628592979751918907">"Ukufakwa ke-WebView"</string>
+ <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Sesba ukufakwa kwe-WebView"</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Phendulisela ekubethelweni kwefayela"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Iyaphendulela..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Sekuvele kubethelwe ngefayela"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 4e88c1c..1bce7f9 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -102,6 +102,7 @@
<!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
<string-array name="select_logd_size_titles">
+ <item>Off</item>
<item>64K</item>
<item>256K</item>
<item>1M</item>
@@ -111,6 +112,7 @@
<!-- Titles for logd limit size lowram selection preference. [CHAR LIMIT=14] -->
<string-array name="select_logd_size_lowram_titles">
+ <item>Off</item>
<item>64K</item>
<item>256K</item>
<item>1M</item>
@@ -118,6 +120,7 @@
<!-- Values for logd limit size selection preference. -->
<string-array name="select_logd_size_values" translatable="false" >
+ <item>32768</item>
<item>65536</item>
<item>262144</item>
<item>1048576</item>
@@ -125,8 +128,9 @@
<item>16777216</item>
</string-array>
- <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=30]-->
+ <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
<string-array name="select_logd_size_summaries" >
+ <item>Off</item>
<item>64K per log buffer</item>
<item>256K per log buffer</item>
<item>1M per log buffer</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7e22881..f7e25db 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -624,6 +624,11 @@
<!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
<string name="force_resizable_activities_summary">Makes all activities resizable for multi-window, regardless of manifest values.</string>
+ <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
+ <string name="enable_freeform_support">Enable freeform windows</string>
+ <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
+ <string name="enable_freeform_support_summary">Enables support for experimental freeform windows.</string>
+
<!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
<string name="local_backup_password_title">Desktop backup password</string>
<!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index 344bf62..f6d9134 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -38,7 +38,7 @@
String packageName = appEntry.info.packageName;
boolean hasPreferred = hasPreferredActivities(pm, packageName)
|| hasUsbDefaults(usbManager, packageName);
- int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId());
+ int status = pm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId());
// consider a visible current link-handling state to be any explicitly designated behavior
boolean hasDomainURLsPreference =
status != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index e6fe447..d353f31e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -316,7 +316,7 @@
synchronized (mEntriesMap) {
AppEntry entry = mEntriesMap.get(userId).get(packageName);
if (entry != null) {
- mPm.getPackageSizeInfo(packageName, userId, mBackgroundHandler.mStatsObserver);
+ mPm.getPackageSizeInfoAsUser(packageName, userId, mBackgroundHandler.mStatsObserver);
}
if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock");
}
@@ -906,7 +906,7 @@
entry.sizeLoadStart = now;
mCurComputingSizePkg = entry.info.packageName;
mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid);
- mPm.getPackageSizeInfo(mCurComputingSizePkg,
+ mPm.getPackageSizeInfoAsUser(mCurComputingSizePkg,
mCurComputingSizeUserId, mStatsObserver);
}
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing");
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index 9790e64..3b818c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -422,7 +422,7 @@
ActivityManager.getCurrentUser(), currentProfiles, finished, count);
for (UserInfo user : users) {
for (ApplicationInfo app : volumeApps) {
- packageManager.getPackageSizeInfo(app.packageName, user.id, observer);
+ packageManager.getPackageSizeInfoAsUser(app.packageName, user.id, observer);
}
}
diff --git a/packages/SettingsProvider/res/values-b+sr+Latn/defaults.xml b/packages/SettingsProvider/res/values-b+sr+Latn/defaults.xml
new file mode 100644
index 0000000..524132e
--- /dev/null
+++ b/packages/SettingsProvider/res/values-b+sr+Latn/defaults.xml
@@ -0,0 +1,25 @@
+<?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">
+ <string name="def_device_name" msgid="6309317409634339402">"%2$s %1$s"</string>
+ <string name="def_device_name_simple" msgid="9037785625140748221">"%1$s"</string>
+ <string name="def_nfc_payment_component" msgid="5861297439873026958"></string>
+</resources>
diff --git a/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..337b18e
--- /dev/null
+++ b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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">
+ <string name="app_label" msgid="4567566098528588863">"Podešavanja skladišta"</string>
+</resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 6680d88..51d8ca0 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -25,6 +25,7 @@
<!-- Comma-separated list of bluetooth, wifi, and cell. -->
<string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
<string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
+ <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
<bool name="def_auto_time">true</bool>
<bool name="def_auto_time_zone">true</bool>
<bool name="def_accelerometer_rotation">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index d4e428e..7338a9c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -116,6 +116,12 @@
// cleaned up automatically when the user is deleted.
File databaseFile = new File(
Environment.getUserSystemDirectory(userHandle), DATABASE_NAME);
+ // If databaseFile doesn't exist, database can be kept in memory. It's safe because the
+ // database will be migrated and disposed of immediately after onCreate finishes
+ if (!databaseFile.exists()) {
+ Log.i(TAG, "No previous database file exists - running in in-memory mode");
+ return null;
+ }
return databaseFile.getPath();
}
}
@@ -130,8 +136,16 @@
return mValidTables.contains(name);
}
+ private boolean isInMemory() {
+ return getDatabaseName() == null;
+ }
+
public void dropDatabase() {
close();
+ // No need to remove files if db is in memory
+ if (isInMemory()) {
+ return;
+ }
File databaseFile = mContext.getDatabasePath(getDatabaseName());
if (databaseFile.exists()) {
databaseFile.delete();
@@ -145,6 +159,10 @@
public void backupDatabase() {
close();
+ // No need to backup files if db is in memory
+ if (isInMemory()) {
+ return;
+ }
File databaseFile = mContext.getDatabasePath(getDatabaseName());
if (!databaseFile.exists()) {
return;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7365e66..bcb459a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1890,7 +1890,7 @@
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 123;
+ private static final int SETTINGS_VERSION = 124;
private final int mUserId;
@@ -2060,6 +2060,16 @@
}
currentVersion = 123;
}
+
+ if (currentVersion == 123) {
+ final SettingsState globalSettings = getGlobalSettingsLocked();
+ String defaultDisabledProfiles = (getContext().getResources().getString(
+ R.string.def_bluetooth_disabled_profiles));
+ globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+ defaultDisabledProfiles, SettingsState.SYSTEM_PACKAGE_NAME);
+ currentVersion = 124;
+ }
+
// vXXX: Add new settings above this point.
// Return the current version.
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 25346ac..c6d9e98 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -107,6 +107,8 @@
<uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
<uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<application android:label="@string/app_label"
android:forceDeviceEncrypted="true"
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
new file mode 100644
index 0000000..5d1e9f9
--- /dev/null
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+ <EditText
+ android:id="@+id/name"
+ android:maxLength="30"
+ android:singleLine="true"
+ android:inputType="textNoSuggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/bugreport_info_name"/>
+ <EditText
+ android:id="@+id/title"
+ android:maxLength="80"
+ android:singleLine="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/bugreport_info_title"/>
+ <EditText
+ android:id="@+id/description"
+ android:singleLine="false"
+ android:inputType="textMultiLine"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/bugreport_info_description"/>
+</LinearLayout>
diff --git a/packages/Shell/res/values-af/strings.xml b/packages/Shell/res/values-af/strings.xml
index 8c4de4e..247ccfc 100644
--- a/packages/Shell/res/values-af/strings.xml
+++ b/packages/Shell/res/values-af/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutverslae"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Foutverslaglêer kon nie gelees word nie"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Besonderhede"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skermkiekie"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skermkiekie suksesvol geneem."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Foutverslagbesonderhede"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kort naam"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-reëlopsomming"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
</resources>
diff --git a/packages/Shell/res/values-am/strings.xml b/packages/Shell/res/values-am/strings.xml
index 415f3ec..9f3615a 100644
--- a/packages/Shell/res/values-am/strings.xml
+++ b/packages/Shell/res/values-am/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"የሳንካ ሪፖርቶች"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"የሳንካ ሪፖርት ፋይል ሊነበብ አልተቻለም"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ያልተሰየመ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"ዝርዝሮች"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ቅጽበታዊ ገጽ እይታ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ቅጽበታዊ ገጽ እይታ በስኬት ተነስቷል።"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"የሳንካ ሪፖርት ዝርዝሮች"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"አጭር ስም"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"የ1 መስመር ማጠቃለያ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
</resources>
diff --git a/packages/Shell/res/values-ar/strings.xml b/packages/Shell/res/values-ar/strings.xml
index 79d615e..b670e37 100644
--- a/packages/Shell/res/values-ar/strings.xml
+++ b/packages/Shell/res/values-ar/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"تقارير الأخطاء"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"تعذرت قراءة ملف تقرير الخطأ."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"بدون اسم"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"التفاصيل"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"لقطة شاشة"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"تم التقاط لقطة الشاشة بنجاح."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"تفاصيل تقرير الخطأ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"اسم مختصر"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"سطر الملخص الأول"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
</resources>
diff --git a/packages/Shell/res/values-az-rAZ/strings.xml b/packages/Shell/res/values-az-rAZ/strings.xml
index 176b009..634d123 100644
--- a/packages/Shell/res/values-az-rAZ/strings.xml
+++ b/packages/Shell/res/values-az-rAZ/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Baq hesabatları"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Baq hesabat faylı oxunmur"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detallar"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"displey görüntüsü"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Displey görüntüsü uğurla çəkildi."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Baq hesabat detalları"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Qısa ad"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-sətrlik xülasə"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
</resources>
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..41acb89
--- /dev/null
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <string name="app_label" msgid="3701846017049540910">"Shell"</string>
+ <string name="bugreport_in_progress_title" msgid="7409917338223386637">"Izveštaj o grešci se generiše"</string>
+ <string name="bugreport_finished_title" msgid="2293711546892863898">"Izveštaj o grešci je snimljen"</string>
+ <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Prevucite ulevo da biste delili izveštaj o greškama"</string>
+ <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Dodirnite da biste delili izveštaj o grešci"</string>
+ <string name="bugreport_confirm" msgid="5130698467795669780">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, uključujući lične i privatne podatke. Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
+ <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Prikaži ovu poruku sledeći put"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
+ <string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteka izveštaja o grešci ne može da se pročita"</string>
+ <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimci ekrana"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snimanje ekrana je uspelo."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalji izveštaja o grešci"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kratki naziv"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Rezime u jednom redu"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
+</resources>
diff --git a/packages/Shell/res/values-bg/strings.xml b/packages/Shell/res/values-bg/strings.xml
index a470998..661a0b65 100644
--- a/packages/Shell/res/values-bg/strings.xml
+++ b/packages/Shell/res/values-bg/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчети за прогр. грешки"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Файлът със сигнал за програмна грешка не можа да бъде прочетен"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"без име"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Подробности"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Екранна снимка"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Екранната снимка бе направена успешно."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Подробности за сигнала за програмна грешка"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Кратко име"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Едноредово обобщение"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
</resources>
diff --git a/packages/Shell/res/values-bn-rBD/strings.xml b/packages/Shell/res/values-bn-rBD/strings.xml
index afa3a46..e7256ca 100644
--- a/packages/Shell/res/values-bn-rBD/strings.xml
+++ b/packages/Shell/res/values-bn-rBD/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ত্রুটির প্রতিবেদনগুলি"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ত্রুটির প্রতিবেদনের ফাইলটি পড়া যায়নি"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"নামবিহীন"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"বিশদ বিবরণ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"স্ক্রীনশট"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"স্ক্রীনশট সফলভাবে নেওয়া হয়েছে৷"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ত্রুটি প্রতিবেদনের বিবরণ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ছোট নাম"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"১-লাইনের সারসংক্ষেপ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
</resources>
diff --git a/packages/Shell/res/values-ca/strings.xml b/packages/Shell/res/values-ca/strings.xml
index 188da67..a8c9553 100644
--- a/packages/Shell/res/values-ca/strings.xml
+++ b/packages/Shell/res/values-ca/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes d\'error"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No s\'ha pogut llegir el fitxer de l\'informe d\'errors"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sense nom"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalls"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla s\'ha fet correctament."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalls de l\'informe d\'errors"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nom curt"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resum d\'una línia"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
</resources>
diff --git a/packages/Shell/res/values-cs/strings.xml b/packages/Shell/res/values-cs/strings.xml
index fdc8023..193501e2 100644
--- a/packages/Shell/res/values-cs/strings.xml
+++ b/packages/Shell/res/values-cs/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Zprávy o chybách"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Soubor chybové zprávy nelze načíst"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímek obrazovky"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímek obrazovky byl úspěšně pořízen."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti zprávy o chybě"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Krátký název"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Shrnutí na jeden řádek"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
</resources>
diff --git a/packages/Shell/res/values-da/strings.xml b/packages/Shell/res/values-da/strings.xml
index 0502655..3975800 100644
--- a/packages/Shell/res/values-da/strings.xml
+++ b/packages/Shell/res/values-da/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fejlrapporter"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fejlrapportfilen kunne ikke læses"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ikke navngivet"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Oplysninger"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skærmbillede"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Der blev taget et skærmbillede."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Fejlrapportoplysninger"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kort navn"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Sammenfatning på én linje"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
</resources>
diff --git a/packages/Shell/res/values-de/strings.xml b/packages/Shell/res/values-de/strings.xml
index 13c1c96..b0450dd 100644
--- a/packages/Shell/res/values-de/strings.xml
+++ b/packages/Shell/res/values-de/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Fehlerberichte"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fehlerberichtdatei konnte nicht gelesen werden."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"Unbenannt"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot wurde aufgenommen."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details des Fehlerberichts"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kurzname"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Zusammenfassung in einer Zeile"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
</resources>
diff --git a/packages/Shell/res/values-el/strings.xml b/packages/Shell/res/values-el/strings.xml
index aa03bec..ec5f3ac 100644
--- a/packages/Shell/res/values-el/strings.xml
+++ b/packages/Shell/res/values-el/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Αναφορές σφαλμάτων"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Δεν ήταν δυνατή η ανάγνωση του αρχείου της αναφοράς σφαλμάτων"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ανώνυμη"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Λεπτομέρειες"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Στιγμιότυπο οθόνης"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Η λήψη του στιγμιότυπου οθόνης ολοκληρώθηκε με επιτυχία."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Λεπτομέρειες αναφοράς σφαλμάτων"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Υποκοριστικό"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Σύνοψη μίας σειράς"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rAU/strings.xml b/packages/Shell/res/values-en-rAU/strings.xml
index a9247d2..26a3d38 100644
--- a/packages/Shell/res/values-en-rAU/strings.xml
+++ b/packages/Shell/res/values-en-rAU/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Short name"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rGB/strings.xml b/packages/Shell/res/values-en-rGB/strings.xml
index a9247d2..26a3d38 100644
--- a/packages/Shell/res/values-en-rGB/strings.xml
+++ b/packages/Shell/res/values-en-rGB/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Short name"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
</resources>
diff --git a/packages/Shell/res/values-en-rIN/strings.xml b/packages/Shell/res/values-en-rIN/strings.xml
index a9247d2..26a3d38 100644
--- a/packages/Shell/res/values-en-rIN/strings.xml
+++ b/packages/Shell/res/values-en-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Bug reports"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bug report file could not be read"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"unnamed"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot taken successfully."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Bug report details"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Short name"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-line summary"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
</resources>
diff --git a/packages/Shell/res/values-es-rUS/strings.xml b/packages/Shell/res/values-es-rUS/strings.xml
index ab2dd63..7f70feb 100644
--- a/packages/Shell/res/values-es-rUS/strings.xml
+++ b/packages/Shell/res/values-es-rUS/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de errores"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No se pudo leer el archivo de informe de errores"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Se tomó la captura de pantalla correctamente."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nombre corto"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumen de una línea"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
</resources>
diff --git a/packages/Shell/res/values-es/strings.xml b/packages/Shell/res/values-es/strings.xml
index d32f012..df080d2 100644
--- a/packages/Shell/res/values-es/strings.xml
+++ b/packages/Shell/res/values-es/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de error"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"No se ha podido leer el archivo del informe de errores"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sin nombre"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La captura de pantalla se ha realizado correctamente."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles del informe de errores"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nombre corto"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumen de 1 línea"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
</resources>
diff --git a/packages/Shell/res/values-et-rEE/strings.xml b/packages/Shell/res/values-et-rEE/strings.xml
index 3edefa4..94b4b89 100644
--- a/packages/Shell/res/values-et-rEE/strings.xml
+++ b/packages/Shell/res/values-et-rEE/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Veaaruanded"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Veaaruande faili ei õnnestunud lugeda"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimeta"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Üksikasjad"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekraanipilt"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekraanipildi tegemine õnnestus."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Veaaruande üksikasjad"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Lühike nimi"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-realine kokkuvõte"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
</resources>
diff --git a/packages/Shell/res/values-eu-rES/strings.xml b/packages/Shell/res/values-eu-rES/strings.xml
index c592f50..cad55fc 100644
--- a/packages/Shell/res/values-eu-rES/strings.xml
+++ b/packages/Shell/res/values-eu-rES/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Akatsen txostenak"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ezin izan da irakurri akatsen txostena"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"izengabea"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Xehetasunak"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pantaila-argazkia"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Atera da pantaila-argazkia."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Akatsen txostenaren xehetasunak"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Izen laburra"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Lerro bakarreko laburpena"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
</resources>
diff --git a/packages/Shell/res/values-fa/strings.xml b/packages/Shell/res/values-fa/strings.xml
index 409fd53..b619f10 100644
--- a/packages/Shell/res/values-fa/strings.xml
+++ b/packages/Shell/res/values-fa/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"گزارش اشکال"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"فایل گزارش اشکال خوانده نشد"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"بینام"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"جزئیات"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"عکس صفحهنمایش"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"عکس صفحهنمایش با موفقیت گرفته شد."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمیتوان عکس صفحهنمایش گرفت."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"جزئیات گزارش اشکال"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"نام مخفف"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"خلاصه یک خطی"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
</resources>
diff --git a/packages/Shell/res/values-fi/strings.xml b/packages/Shell/res/values-fi/strings.xml
index bfa920a..a90ffb5 100644
--- a/packages/Shell/res/values-fi/strings.xml
+++ b/packages/Shell/res/values-fi/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Virheraportit"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Virheraporttitiedostoa ei voi lukea."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"nimetön"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Tietoja"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Kuvakaappaus"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Kuvakaappaus tallennettu."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Virheraportin tiedot"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Lyhyt nimi"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Lyhyt tiivistelmä"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
</resources>
diff --git a/packages/Shell/res/values-fr-rCA/strings.xml b/packages/Shell/res/values-fr-rCA/strings.xml
index 4dc4482..52be99d 100644
--- a/packages/Shell/res/values-fr-rCA/strings.xml
+++ b/packages/Shell/res/values-fr-rCA/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports de bogues"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier du rapport de bogue"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Saisie d\'écran"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La saisie d\'écran a réussi."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bogue"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nom abrégé"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Résumé d\'une ligne"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
</resources>
diff --git a/packages/Shell/res/values-fr/strings.xml b/packages/Shell/res/values-fr/strings.xml
index a3e4f7d..e10e28e 100644
--- a/packages/Shell/res/values-fr/strings.xml
+++ b/packages/Shell/res/values-fr/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapports d\'erreur"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossible de lire le fichier de rapport de bug."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sans nom"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Détails"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captures d\'écran"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"La capture d\'écran a bien été effectuée."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Détails du rapport de bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nom court"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Résumé d\'une ligne"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
</resources>
diff --git a/packages/Shell/res/values-gl-rES/strings.xml b/packages/Shell/res/values-gl-rES/strings.xml
index 8b28caa..20f8cda 100644
--- a/packages/Shell/res/values-gl-rES/strings.xml
+++ b/packages/Shell/res/values-gl-rES/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Informes de erros"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Non se puido ler o ficheiro de informe de erros"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sen nome"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalles"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de pantalla"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"A captura de pantalla realizouse correctamente."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalles do informe de erros"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nome abreviado"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumo de 1 liña"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
</resources>
diff --git a/packages/Shell/res/values-gu-rIN/strings.xml b/packages/Shell/res/values-gu-rIN/strings.xml
index 91b1362..967d255 100644
--- a/packages/Shell/res/values-gu-rIN/strings.xml
+++ b/packages/Shell/res/values-gu-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"બગ રિપોર્ટ્સ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"બગ રીપોર્ટ ફાઇલ વાંચી શકાઇ નથી"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"અનામાંકિત"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"વિગતો"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"સ્ક્રીનશોટ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"સ્ક્રીનશોટ સફળતાપૂર્વક લેવાયો."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"બગ રિપોર્ટની વિગતો"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"નાનું નામ"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-રેખાનો સારાંશ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
</resources>
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 595ec7f..70e4f38 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्ट"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फ़ाइल नहीं पढ़ी जा सकी"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामांकित"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्ट के विवरण"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"संक्षिप्त नाम"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-पंक्ति में सारांश"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
</resources>
diff --git a/packages/Shell/res/values-hr/strings.xml b/packages/Shell/res/values-hr/strings.xml
index 1957bdb..f38a281 100644
--- a/packages/Shell/res/values-hr/strings.xml
+++ b/packages/Shell/res/values-hr/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Izvj. o prog. pogreš."</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Izvješće o programskoj pogrešci nije pročitano"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez naziva"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Pojedinosti"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimka zaslona"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zaslon je snimljen."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Pojedinosti izvješća o programskoj pogrešci"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kratko ime"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Sažetak u jednom retku"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
</resources>
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 74b4aba..544c117 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hibajelentések"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"A hibajelentési fájlt nem sikerült beolvasni"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"névtelen"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Részletek"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Képernyőkép"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Sikerült elkészíteni a képernyőképet."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hibajelentés részletei"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Rövid név"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Egysoros összefoglalás"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
</resources>
diff --git a/packages/Shell/res/values-hy-rAM/strings.xml b/packages/Shell/res/values-hy-rAM/strings.xml
index 317cb0b..625994d 100644
--- a/packages/Shell/res/values-hy-rAM/strings.xml
+++ b/packages/Shell/res/values-hy-rAM/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Վրիպակների հաշվետվություններ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Հնարավոր չէ կարդալ վրիպակների զեկույցի ֆայլը"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"անանուն"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Մանրամասներ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Էկրանի պատկեր"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Էկրանի պատկերը հաջողությամբ ստացվեց:"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Վրիպակի զեկույցի մանրամասները"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Կրճատ անուն"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Ամփոփագիր մեկ տողով"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
</resources>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index 57d4c73..747fecd 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"File laporan bug tidak dapat dibaca"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"tanpa nama"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detail"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan layar"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan layar berhasil diambil."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detail laporan bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nama pendek"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Ringkasan 1 baris"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
</resources>
diff --git a/packages/Shell/res/values-is-rIS/strings.xml b/packages/Shell/res/values-is-rIS/strings.xml
index 39605db..d0d3e60 100644
--- a/packages/Shell/res/values-is-rIS/strings.xml
+++ b/packages/Shell/res/values-is-rIS/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Villutilkynningar"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ekki var hægt að lesa úr villuskýrslunni"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"án heitis"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Nánar"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjámynd"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tókst að taka skjámynd."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Upplýsingar um villutilkynningu"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Stutt heiti"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Einnar línu samantekt"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
</resources>
diff --git a/packages/Shell/res/values-it/strings.xml b/packages/Shell/res/values-it/strings.xml
index 10ba7dd..0511c58 100644
--- a/packages/Shell/res/values-it/strings.xml
+++ b/packages/Shell/res/values-it/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapporti sui bug"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Impossibile leggere il file relativo alla segnalazione di bug"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"senza nome"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Dettagli"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot acquisito."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Dettagli della segnalazione di bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nome breve"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Sintesi su una riga"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
</resources>
diff --git a/packages/Shell/res/values-iw/strings.xml b/packages/Shell/res/values-iw/strings.xml
index 5b0cb26..b9bcaf9 100644
--- a/packages/Shell/res/values-iw/strings.xml
+++ b/packages/Shell/res/values-iw/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"דוחות באגים"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"לא ניתן היה לקרוא את קובץ הדוח על הבאג"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ללא שם"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"פרטים"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"צילום מסך"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"צילום המסך בוצע בהצלחה."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"פרטי דוח על באג"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"כינוי"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"סיכום בשורה אחת"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
</resources>
diff --git a/packages/Shell/res/values-ja/strings.xml b/packages/Shell/res/values-ja/strings.xml
index fd4a150..05b95eb 100644
--- a/packages/Shell/res/values-ja/strings.xml
+++ b/packages/Shell/res/values-ja/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"バグレポート"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"バグレポート ファイルを読み取ることができませんでした"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"名前なし"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"詳細"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"スクリーンショット"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"スクリーンショットを撮影しました。"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"バグレポートの詳細"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"省略名"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 行の概要"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
</resources>
diff --git a/packages/Shell/res/values-ka-rGE/strings.xml b/packages/Shell/res/values-ka-rGE/strings.xml
index 802f944..2cfd80a 100644
--- a/packages/Shell/res/values-ka-rGE/strings.xml
+++ b/packages/Shell/res/values-ka-rGE/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"შეცდომების ანგარიშები"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ხარვეზების შესახებ ანგარიშის წაკითხვა ვერ მოხერხდა"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"უსახელო"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"დეტალები"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ეკრანის ანაბეჭდი"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ეკრანის ანაბეჭდი გადაღებულია წარმატებით."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ხარვეზის შესახებ ანგარიშის დეტალები"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"მოკლე სახელი"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-ხაზიანი რეზიუმე"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
</resources>
diff --git a/packages/Shell/res/values-kk-rKZ/strings.xml b/packages/Shell/res/values-kk-rKZ/strings.xml
index 2825342..2829b9b 100644
--- a/packages/Shell/res/values-kk-rKZ/strings.xml
+++ b/packages/Shell/res/values-kk-rKZ/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Қате туралы баяндамалар"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Қате туралы есеп файлын оқу мүмкін болмады"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"атаусыз"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Мәліметтер"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот сәтті түсірілді."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Қате туралы есептің мәліметтері"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Қысқа аты"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 жолдық жиынтық мәліметтер"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
</resources>
diff --git a/packages/Shell/res/values-km-rKH/strings.xml b/packages/Shell/res/values-km-rKH/strings.xml
index 966cec0..3573588 100644
--- a/packages/Shell/res/values-km-rKH/strings.xml
+++ b/packages/Shell/res/values-km-rKH/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"រាយការណ៍ពីកំហុស"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"មិនអាចអានឯកសាររបាយកាណ៍កំហុសបានទេ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"គ្មានឈ្មោះ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"ព័ត៌មានលម្អិត"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"រូបថតអេក្រង់"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"បានថតរូបថតអេក្រង់ដោយជោគជ័យ"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ព័ត៌មានលម្អិតពីរបាយការណ៍កំហុស"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ឈ្មោះខ្លី"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"ការសង្ខេបមួយជួរ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
</resources>
diff --git a/packages/Shell/res/values-kn-rIN/strings.xml b/packages/Shell/res/values-kn-rIN/strings.xml
index 6da5319..7071264 100644
--- a/packages/Shell/res/values-kn-rIN/strings.xml
+++ b/packages/Shell/res/values-kn-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ದೋಷ ವರದಿಗಳು"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ಬಗ್ ವರದಿ ಫೈಲ್ ಅನ್ನು ಓದಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ಹೆಸರಿಸದಿರುವುದು"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"ವಿವರಗಳು"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಯಶಸ್ವಿಯಾಗಿ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ಬಗ್ ವರದಿ ವಿವರಗಳು"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ಚಿಕ್ಕ ಹೆಸರು"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-ಸಾಲಿನ ಸಾರಾಂಶ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
</resources>
diff --git a/packages/Shell/res/values-ko/strings.xml b/packages/Shell/res/values-ko/strings.xml
index 5e96e6d..4e3c3f4 100644
--- a/packages/Shell/res/values-ko/strings.xml
+++ b/packages/Shell/res/values-ko/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"버그 신고"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"버그 신고 파일을 읽을 수 없습니다."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"이름 없음"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"세부정보"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"스크린샷"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"스크린샷을 찍었습니다."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"버그 신고 세부정보"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"짧은 이름"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"한 줄 요약"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
</resources>
diff --git a/packages/Shell/res/values-ky-rKG/strings.xml b/packages/Shell/res/values-ky-rKG/strings.xml
index c5b4144..051be38 100644
--- a/packages/Shell/res/values-ky-rKG/strings.xml
+++ b/packages/Shell/res/values-ky-rKG/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Мүчүлүштүктөрдү кабарлоолор"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Мүчүлүштүк тууралуу кабарлаган файл окулбай койду"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"аталышы жок"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Чоо-жайы"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншот"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот ийгиликтүү тартылды."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Мүчүлүштүктөр жөнүндө кабардын чоо-жайы"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Кыска аталышы"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 саптык корутунду"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
</resources>
diff --git a/packages/Shell/res/values-lo-rLA/strings.xml b/packages/Shell/res/values-lo-rLA/strings.xml
index 0346688..a04a3556 100644
--- a/packages/Shell/res/values-lo-rLA/strings.xml
+++ b/packages/Shell/res/values-lo-rLA/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ລາຍງານບັນຫາ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ບໍ່ສາມາດອ່ານໄຟລ໌ລາຍງານຂໍ້ຜິດພາດໄດ້"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ບໍ່ມີຊື່"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"ລາຍລະອຽດ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ພາບໜ້າຈໍ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ຖ່າຍພາບໜ້າຈໍສຳເລັດແລ້ວ."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ລາຍລະອຽດການລາຍງານບັນຫາ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ຊື່ສັ້ນ"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"ສະຫຼຸບ 1 ແຖວ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
</resources>
diff --git a/packages/Shell/res/values-lt/strings.xml b/packages/Shell/res/values-lt/strings.xml
index 84066c0..8d8d31e 100644
--- a/packages/Shell/res/values-lt/strings.xml
+++ b/packages/Shell/res/values-lt/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Riktų ataskaitos"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nepavyko sukurti pranešimo apie riktą failo"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"be pavadinimo"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Informacija"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrano kopija"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrano kopija sėkmingai padaryta."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Išsami pranešimo apie riktą informacija"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Trumpasis pavadinimas"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 eilutės suvestinė"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
</resources>
diff --git a/packages/Shell/res/values-lv/strings.xml b/packages/Shell/res/values-lv/strings.xml
index 95d168c..dba1ad3 100644
--- a/packages/Shell/res/values-lv/strings.xml
+++ b/packages/Shell/res/values-lv/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Kļūdu ziņojumi"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nevarēja nolasīt kļūdas pārskata failu."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nosaukuma"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalizēta informācija"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekrānuzņēmums"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekrānuzņēmums ir veikts sekmīgi."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Kļūdas pārskata informācija"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Saīsināts nosaukums"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Kopsavilkums 1 rindiņā"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
</resources>
diff --git a/packages/Shell/res/values-mk-rMK/strings.xml b/packages/Shell/res/values-mk-rMK/strings.xml
index 0f3ed5a..6e23ad8 100644
--- a/packages/Shell/res/values-mk-rMK/strings.xml
+++ b/packages/Shell/res/values-mk-rMK/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаи за грешки"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Датотеката со извештај за грешка не можеше да се прочита"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименувани"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Слика од екранот"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Успешно е направена слика од екранот."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали на извештајот за грешка"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Кратко име"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Резиме во 1 ред"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
</resources>
diff --git a/packages/Shell/res/values-ml-rIN/strings.xml b/packages/Shell/res/values-ml-rIN/strings.xml
index 290c10b..73a4fff 100644
--- a/packages/Shell/res/values-ml-rIN/strings.xml
+++ b/packages/Shell/res/values-ml-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ബഗ് റിപ്പോർട്ടുകൾ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ബഗ് റിപ്പോർട്ട് ഫയൽ വായിക്കാനായില്ല"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"പേരില്ലാത്തവർ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"വിശദാംശങ്ങൾ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"സ്ക്രീൻഷോട്ട്"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"സ്ക്രീൻഷോട്ട് എടുത്തു."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ബഗ് റിപ്പോർട്ട് വിശദാംശങ്ങൾ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ഹ്രസ്വ നാമം"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"ഒരു വരി സംഗ്രഹം"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
</resources>
diff --git a/packages/Shell/res/values-mn-rMN/strings.xml b/packages/Shell/res/values-mn-rMN/strings.xml
index 8f6a2b0..1f4be4ab 100644
--- a/packages/Shell/res/values-mn-rMN/strings.xml
+++ b/packages/Shell/res/values-mn-rMN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Гэмтлийн тухай тайлан"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Алдааны тайлангийн файлыг уншиж чадахгүй байна"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"нэр байхгүй"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Дэлгэрэнгүй"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Дэлгэцийн зураг"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Дэлгэцийн зургийг амжилттай авлаа."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Алдааны дэлгэрэнгүй тайлан"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Богино нэр"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-р шугамын хураангуй"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
</resources>
diff --git a/packages/Shell/res/values-mr-rIN/strings.xml b/packages/Shell/res/values-mr-rIN/strings.xml
index 40d7a9c..6b06cf5 100644
--- a/packages/Shell/res/values-mr-rIN/strings.xml
+++ b/packages/Shell/res/values-mr-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"दोष अहवाल"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"दोष अहवाल फाईल वाचणे शक्य झाले नाही"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामित"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"तपशील"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रीनशॉट यशस्वीपणे घेतला."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"दोष अहवाल तपशील"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"लघु नाव"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-ओळीचा सारांश"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
</resources>
diff --git a/packages/Shell/res/values-ms-rMY/strings.xml b/packages/Shell/res/values-ms-rMY/strings.xml
index db8b5dc..e22f880 100644
--- a/packages/Shell/res/values-ms-rMY/strings.xml
+++ b/packages/Shell/res/values-ms-rMY/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan pepijat"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fail laporan pepijat tidak dapat dibaca"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"tidak bernama"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Butiran"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan skrin"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Tangkapan skrin berjaya diambil."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Butiran laporan pepijat"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nama pendek"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Ringkasan 1 baris"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
</resources>
diff --git a/packages/Shell/res/values-my-rMM/strings.xml b/packages/Shell/res/values-my-rMM/strings.xml
index 77ca5bf..727cdc9 100644
--- a/packages/Shell/res/values-my-rMM/strings.xml
+++ b/packages/Shell/res/values-my-rMM/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ချို့ယွင်းမှု အစီရင်ခံစာများ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ချွတ်ယွင်းချက် အစီရင်ခံစာကို ဖတ်၍မရပါ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"အမည်မဲ့"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"အသေးစိတ်များ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံကို အောင်မြင်စွာ ရိုက်ပြီးပြီ။"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ချွတ်ယွင်းချက်အစီရင်ခံစာ အသေးစိတ်များ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"အမည်အတိုကောက်"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"လိုင်း ၁ လိုင်းအကျဉ်းချုပ်"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
</resources>
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 14a873c..c7702ef 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Feilrapporter"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Feilrapportfilen kunne ikke leses"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"uten navn"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detaljer"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skjermdumpen er tatt."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detaljer om feilrapporten"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kallenavn"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Sammendrag på én linje"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
</resources>
diff --git a/packages/Shell/res/values-ne-rNP/strings.xml b/packages/Shell/res/values-ne-rNP/strings.xml
index 03aef3c..732f398 100644
--- a/packages/Shell/res/values-ne-rNP/strings.xml
+++ b/packages/Shell/res/values-ne-rNP/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्टहरू"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फाइल पढ्न सकिएन"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"(नामविहीन)"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रिनशट"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"स्क्रिनशट सफलतापूर्वक लिइयो।"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"बग रिपोर्टको विवरण"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"छोटो नाम"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"१ लाइनको सारांश"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
</resources>
diff --git a/packages/Shell/res/values-nl/strings.xml b/packages/Shell/res/values-nl/strings.xml
index 9bfce94..0378ca4a 100644
--- a/packages/Shell/res/values-nl/strings.xml
+++ b/packages/Shell/res/values-nl/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Foutenrapporten"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Bestand met bugrapport kan niet worden gelezen"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"naamloos"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Details"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Screenshot is gemaakt."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Details van bugrapport"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Korte naam"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Samenvatting van één regel"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
</resources>
diff --git a/packages/Shell/res/values-pa-rIN/strings.xml b/packages/Shell/res/values-pa-rIN/strings.xml
index cf6df17..720bde0 100644
--- a/packages/Shell/res/values-pa-rIN/strings.xml
+++ b/packages/Shell/res/values-pa-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"ਬਗ ਰਿਪੋਰਟਾਂ"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ਬਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਪੜ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕੀ"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ਬਿਨਾਂ-ਨਾਮ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"ਵੇਰਵੇ"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸਫਲਤਾਪੂਰਵਕ ਲਿਆ ਗਿਆ।"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"ਬੱਗ ਰਿਪੋਰਟ ਵੇਰਵੇ"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ਛੋਟਾ ਨਾਮ"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-ਲਾਈਨ ਸਾਰਾਂਸ਼"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
</resources>
diff --git a/packages/Shell/res/values-pl/strings.xml b/packages/Shell/res/values-pl/strings.xml
index 0c8a6b4..d6715a5 100644
--- a/packages/Shell/res/values-pl/strings.xml
+++ b/packages/Shell/res/values-pl/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raporty o błędach"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Nie można odczytać raportu o błędzie"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez nazwy"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Szczegóły"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Zrzut ekranu"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Zrobiono zrzut ekranu."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Szczegóły zgłoszenia błędu"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Krótka nazwa"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Jednowierszowe podsumowanie"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
</resources>
diff --git a/packages/Shell/res/values-pt-rBR/strings.xml b/packages/Shell/res/values-pt-rBR/strings.xml
index b194ecc..fb16dd8 100644
--- a/packages/Shell/res/values-pt-rBR/strings.xml
+++ b/packages/Shell/res/values-pt-rBR/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Apelido"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumo de uma linha"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
</resources>
diff --git a/packages/Shell/res/values-pt-rPT/strings.xml b/packages/Shell/res/values-pt-rPT/strings.xml
index 757538c..07d319e 100644
--- a/packages/Shell/res/values-pt-rPT/strings.xml
+++ b/packages/Shell/res/values-pt-rPT/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de erros"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o ficheiro de relatório de erro"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captura de ecrã"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecrã tirada com êxito."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório de erro"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nome abreviado"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumo de 1 linha"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
</resources>
diff --git a/packages/Shell/res/values-pt/strings.xml b/packages/Shell/res/values-pt/strings.xml
index b194ecc..fb16dd8 100644
--- a/packages/Shell/res/values-pt/strings.xml
+++ b/packages/Shell/res/values-pt/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Relatórios de bugs"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Não foi possível ler o arquivo de relatório de bug"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"sem nome"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalhes"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Capturas de tela"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de tela concluída."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalhes do relatório do bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Apelido"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Resumo de uma linha"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
</resources>
diff --git a/packages/Shell/res/values-ro/strings.xml b/packages/Shell/res/values-ro/strings.xml
index 132f21f..064dfaf7 100644
--- a/packages/Shell/res/values-ro/strings.xml
+++ b/packages/Shell/res/values-ro/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Rapoarte de erori"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Fișierul cu raportul de eroare nu a putut fi citit"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"fără nume"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detalii"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Captură de ecran"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Captura de ecran a fost făcută."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detalii privind raportul de eroare"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Nume scurt"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Rezumat de un rând"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
</resources>
diff --git a/packages/Shell/res/values-ru/strings.xml b/packages/Shell/res/values-ru/strings.xml
index 5dc5953..3350740 100644
--- a/packages/Shell/res/values-ru/strings.xml
+++ b/packages/Shell/res/values-ru/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Отчеты об ошибках"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Не удалось открыть отчет об ошибке"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"без названия"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Детали"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Скриншоты"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Скриншот готов"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детали отчета об ошибке"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Краткое название"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Краткое описание ошибки"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
</resources>
diff --git a/packages/Shell/res/values-si-rLK/strings.xml b/packages/Shell/res/values-si-rLK/strings.xml
index c846f87..d915109 100644
--- a/packages/Shell/res/values-si-rLK/strings.xml
+++ b/packages/Shell/res/values-si-rLK/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"දෝෂ වාර්තා"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"දෝෂ වාර්තා ගොනුව කියවීමට නොහැකි විය"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"නම් නොකළ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"විස්තර"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"තිර රුව"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"සාර්ථකව තිර රුවක් ගන්නා ලදී."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"දෝෂ වාර්තා විස්තර"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"කෙටි නම"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"පේළි-1 සාරාංශය"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
</resources>
diff --git a/packages/Shell/res/values-sk/strings.xml b/packages/Shell/res/values-sk/strings.xml
index b395d1a..ec9003d 100644
--- a/packages/Shell/res/values-sk/strings.xml
+++ b/packages/Shell/res/values-sk/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hlásenia chýb"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Súbor s hlásením chyby sa nepodarilo prečítať"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"bez názvu"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snímka obrazovky"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Snímka obrazovky bola zaznamenaná."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti hlásenia chyby"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Skrátený názov"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Jednoriadkové zhrnutie"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
</resources>
diff --git a/packages/Shell/res/values-sl/strings.xml b/packages/Shell/res/values-sl/strings.xml
index 91041e1..aa66ce9 100644
--- a/packages/Shell/res/values-sl/strings.xml
+++ b/packages/Shell/res/values-sl/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Poročila o napakah"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteke s poročilom o napakah ni bilo mogoče prebrati"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Podrobnosti"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Posnetek zaslona"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Posnetek zaslon je bil uspešno ustvarjen."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Podrobnosti o poročilu o napakah"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Ime"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Enovrstični povzetek"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
</resources>
diff --git a/packages/Shell/res/values-sq-rAL/strings.xml b/packages/Shell/res/values-sq-rAL/strings.xml
index e91aa09..dd13f34 100644
--- a/packages/Shell/res/values-sq-rAL/strings.xml
+++ b/packages/Shell/res/values-sq-rAL/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Raportet e gabimeve"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Skedari i raportimit të defektit në kod nuk mund të lexohej."</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"e paemërtuar"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Detajet"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Pamja e ekranit"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Pamja e ekranit u realizua me sukses."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Detajet e raportimit të gabimeve në kod"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Emri shkurt"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Përmbledhje me 1 rresht"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
</resources>
diff --git a/packages/Shell/res/values-sr/strings.xml b/packages/Shell/res/values-sr/strings.xml
index 1be47da..1da7ecb 100644
--- a/packages/Shell/res/values-sr/strings.xml
+++ b/packages/Shell/res/values-sr/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Извештаји о грешкама"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Датотека извештаја о грешци не може да се прочита"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"неименовано"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Детаљи"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Снимци екрана"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Снимање екрана је успело."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Детаљи извештаја о грешци"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Кратки назив"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Резиме у једном реду"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
</resources>
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 9f5b5f0..8afa0a5 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Felrapporter"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Det gick inte att läsa felrapporten"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"namnlös"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Information"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skärmdump"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"En skärmdump har tagits."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Information för felrapporten"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kortnamn"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Sammanfattning på en rad"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
</resources>
diff --git a/packages/Shell/res/values-sw/strings.xml b/packages/Shell/res/values-sw/strings.xml
index 422ca81..5b70262 100644
--- a/packages/Shell/res/values-sw/strings.xml
+++ b/packages/Shell/res/values-sw/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Ripoti za hitilafu"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Faili ya ripoti ya hitilafu haikusomwa"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"Isiyo na jina"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Maelezo"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Picha ya skrini"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Imepiga picha ya skrini."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Maelezo kuhusu ripoti ya hitilafu"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Jina fupi"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Muhtasari wa mstari mmoja"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
</resources>
diff --git a/packages/Shell/res/values-ta-rIN/strings.xml b/packages/Shell/res/values-ta-rIN/strings.xml
index 31daf54..91eb718 100644
--- a/packages/Shell/res/values-ta-rIN/strings.xml
+++ b/packages/Shell/res/values-ta-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"பிழை அறிக்கைகள்"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"பிழை அறிக்கையைப் படிக்க முடியவில்லை"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"பெயரிடப்படாதது"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"விவரங்கள்"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ஸ்கிரீன் ஷாட்"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"பிழை அறிக்கை விவரங்கள்"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"சுருக்கப் பெயர்"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"சுருக்கவிவரம் (ஒரு வரியில்)"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
</resources>
diff --git a/packages/Shell/res/values-te-rIN/strings.xml b/packages/Shell/res/values-te-rIN/strings.xml
index 34ab6f2..517dd5e 100644
--- a/packages/Shell/res/values-te-rIN/strings.xml
+++ b/packages/Shell/res/values-te-rIN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"బగ్ నివేదికలు"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"బగ్ నివేదిక ఫైల్ను చదవడం సాధ్యపడలేదు"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"పేరు లేనివి"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"వివరాలు"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"స్క్రీన్షాట్"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"స్క్రీన్షాట్ విజయవంతంగా తీయబడింది."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్షాట్ను తీయడం సాధ్యపడలేదు."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"బగ్ నివేదిక వివరాలు"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"చిన్న పేరు"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1-పంక్తి సారాంశం"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
</resources>
diff --git a/packages/Shell/res/values-th/strings.xml b/packages/Shell/res/values-th/strings.xml
index 2d9a65e..b734095 100644
--- a/packages/Shell/res/values-th/strings.xml
+++ b/packages/Shell/res/values-th/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"รายงานข้อบกพร่อง"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"ไม่สามารถอ่านไฟล์รายงานข้อบกพร่อง"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"ไม่มีชื่อ"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"รายละเอียด"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"ภาพหน้าจอ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"จับภาพหน้าจอสำเร็จแล้ว"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"รายละเอียดรายงานข้อบกพร่อง"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"ชื่อย่อ"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"สรุป 1 บรรทัด"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
</resources>
diff --git a/packages/Shell/res/values-tl/strings.xml b/packages/Shell/res/values-tl/strings.xml
index 8fead8f..bcce1db 100644
--- a/packages/Shell/res/values-tl/strings.xml
+++ b/packages/Shell/res/values-tl/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Mga ulat sa bug"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Hindi mabasa ang file ng pag-uulat ng bug"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"walang pangalan"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Mga Detalye"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Nakunan ng screenshot."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Mga detalye ng ulat ng bug"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Maikling pangalan"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Buod na may 1 linya"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
</resources>
diff --git a/packages/Shell/res/values-tr/strings.xml b/packages/Shell/res/values-tr/strings.xml
index e1d30cc..e1fdf10 100644
--- a/packages/Shell/res/values-tr/strings.xml
+++ b/packages/Shell/res/values-tr/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Hata raporları"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Hata raporu dosyası okunamadı"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"adsız"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Ayrıntılar"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ekran görüntüsü"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Ekran görüntüsü başarıyla alındı."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Hata raporu ayrıntıları"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Kısa ad"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 satırlık özet"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
</resources>
diff --git a/packages/Shell/res/values-uk/strings.xml b/packages/Shell/res/values-uk/strings.xml
index f1396cb..dd43c4c 100644
--- a/packages/Shell/res/values-uk/strings.xml
+++ b/packages/Shell/res/values-uk/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Звіти про помилки"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Не вдалося прочитати звіт про помилки"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"без назви"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Деталі"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Знімок екрана"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Знімок екрана зроблено."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Деталі повідомлення про помилку"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Коротка назва"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Підсумок одним рядком"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
</resources>
diff --git a/packages/Shell/res/values-ur-rPK/strings.xml b/packages/Shell/res/values-ur-rPK/strings.xml
index 412d230..b97c8b5 100644
--- a/packages/Shell/res/values-ur-rPK/strings.xml
+++ b/packages/Shell/res/values-ur-rPK/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"بگ رپورٹس"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"بگ رپورٹ فائل پڑھی نہیں جا سکی"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"بغیر نام"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"تفصیلات"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"اسکرین شاٹ"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"اسکرین شاٹ کامیابی سے لے لیا گیا۔"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"بگ رپورٹ کی تفصیلات"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"مختصر نام"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"1 لائن کا خلاصہ"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
</resources>
diff --git a/packages/Shell/res/values-uz-rUZ/strings.xml b/packages/Shell/res/values-uz-rUZ/strings.xml
index ca46d2a..279c876 100644
--- a/packages/Shell/res/values-uz-rUZ/strings.xml
+++ b/packages/Shell/res/values-uz-rUZ/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Xatoliklar hisoboti"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Xatoliklar hisoboti faylini o‘qib bo‘lmadi"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"nomsiz"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Tafsilotlar"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skrinshot"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Skrinshot tayyor."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Xatoliklar hisoboti tafsilotlari"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Qisqa nomi"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Xatolikning qisqacha ta’rifi"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
</resources>
diff --git a/packages/Shell/res/values-vi/strings.xml b/packages/Shell/res/values-vi/strings.xml
index ec4364e..4e1ebc7 100644
--- a/packages/Shell/res/values-vi/strings.xml
+++ b/packages/Shell/res/values-vi/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Báo cáo lỗi"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Không thể đọc tệp báo cáo lỗi"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"chưa được đặt tên"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Chi tiết"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Ảnh chụp màn hình"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Đã chụp ảnh màn hình thành công."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Chi tiết báo cáo lỗi"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Tên ngắn"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Tóm tắt 1 dòng"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rCN/strings.xml b/packages/Shell/res/values-zh-rCN/strings.xml
index 5a8e5f7..b5ba7a9 100644
--- a/packages/Shell/res/values-zh-rCN/strings.xml
+++ b/packages/Shell/res/values-zh-rCN/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"错误报告"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"无法读取错误报告文件"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"详细信息"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"屏幕截图"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功截图。"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"错误报告详细信息"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"简称"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"简短摘要(1 行)"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rHK/strings.xml b/packages/Shell/res/values-zh-rHK/strings.xml
index 7e57cc4..896a920 100644
--- a/packages/Shell/res/values-zh-rHK/strings.xml
+++ b/packages/Shell/res/values-zh-rHK/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"無法讀取錯誤報告檔案"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"詳細資訊"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳情"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"簡稱"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"簡短摘要 (1 行)"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
</resources>
diff --git a/packages/Shell/res/values-zh-rTW/strings.xml b/packages/Shell/res/values-zh-rTW/strings.xml
index e495d4a..2bdf561 100644
--- a/packages/Shell/res/values-zh-rTW/strings.xml
+++ b/packages/Shell/res/values-zh-rTW/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"錯誤報告"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"無法讀取錯誤報告檔案"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"未命名"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"詳細資料"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"螢幕擷取畫面"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"已成功拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"錯誤報告詳細資料"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"簡稱"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"簡短摘要"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
</resources>
diff --git a/packages/Shell/res/values-zu/strings.xml b/packages/Shell/res/values-zu/strings.xml
index 91f2951..652105a 100644
--- a/packages/Shell/res/values-zu/strings.xml
+++ b/packages/Shell/res/values-zu/strings.xml
@@ -26,4 +26,12 @@
<string name="bugreport_storage_title" msgid="5332488144740527109">"Imibiko yeziphazamiso"</string>
<string name="bugreport_unreadable_text" msgid="586517851044535486">"Ifayela lombiko wesiphazamso alikwazanga ukufundwa"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"awunikiwe igama"</string>
+ <string name="bugreport_info_action" msgid="2158204228510576227">"Imininingwane"</string>
+ <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Isithombe-skrini"</string>
+ <string name="bugreport_screenshot_taken" msgid="7175343181767429088">"Isithombe-skrini sithathwe ngempumelelo."</string>
+ <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
+ <string name="bugreport_info_dialog_title" msgid="3113549839798564645">"Imininingwane yombiko wesiphazamisi"</string>
+ <string name="bugreport_info_name" msgid="5089191832271852826">"Igama elifishane"</string>
+ <string name="bugreport_info_title" msgid="127167853370557175">"Isifinyezo somugqa ongu-1"</string>
+ <string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
</resources>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 5c25576..dcd5f04 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -42,4 +42,27 @@
<!-- Title for bug reports received from dumpstate without a name. [CHAR LIMIT=30]-->
<string name="bugreport_unnamed">unnamed</string>
+ <!-- Title of the notification action that opens the dialog for the user-defined bug report details. -->
+ <string name="bugreport_info_action">Details</string>
+
+ <!-- Title of the notification action that takes aditional screenshots. -->
+ <string name="bugreport_screenshot_action">Screenshot</string>
+
+ <!-- Toast message sent when the a screenshot for the bug report was taken successfully. -->
+ <string name="bugreport_screenshot_taken">Screenshot taken succesfully.</string>
+ <!-- Toast message sent when the a screenshot for the bug report was not taken due to an error. -->
+ <string name="bugreport_screenshot_failed">Screenshot could not be taken.</string>
+
+ <!-- Title of the dialog asking for user-defined bug report details like name, title, and description. -->
+ <string name="bugreport_info_dialog_title">Bug report details</string>
+
+ <!-- Text of the hint asking for the bug report name, which when set will define a suffix in the
+ bug report file names. [CHAR LIMIT=30] -->
+ <string name="bugreport_info_name">Short name</string>
+ <!-- Text of hint asking for the bug report title, which when set will define the
+ Subject of the email message. [CHAR LIMIT=60] -->
+ <string name="bugreport_info_title">1-line summary</string>
+ <!-- Text of hint asking for the bug report description, which when set will describe
+ what the bug report is about. [CHAR LIMIT=NONE] -->
+ <string name="bugreport_info_description">Detailed description</string>
</resources>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index e902589..00a6cbd 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -16,10 +16,12 @@
package com.android.shell;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.shell.BugreportPrefs.STATE_SHOW;
import static com.android.shell.BugreportPrefs.getWarningState;
import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -27,18 +29,24 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
import java.text.NumberFormat;
import java.util.ArrayList;
-import java.util.Date;
+import java.util.Enumeration;
+import java.util.List;
import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import libcore.io.Streams;
+import com.android.internal.annotations.VisibleForTesting;
import com.google.android.collect.Lists;
import android.accounts.Account;
import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
import android.app.Notification;
import android.app.Notification.Action;
import android.app.NotificationManager;
@@ -46,6 +54,8 @@
import android.app.Service;
import android.content.ClipData;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
@@ -56,13 +66,20 @@
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
-import android.os.Process;
import android.os.SystemProperties;
+import android.os.Vibrator;
import android.support.v4.content.FileProvider;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Patterns;
import android.util.SparseArray;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.View.OnFocusChangeListener;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
import android.widget.Toast;
/**
@@ -103,19 +120,35 @@
// Internal intents used on notification actions.
static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL";
static final String INTENT_BUGREPORT_SHARE = "android.intent.action.BUGREPORT_SHARE";
+ static final String INTENT_BUGREPORT_INFO_LAUNCH =
+ "android.intent.action.BUGREPORT_INFO_LAUNCH";
+ static final String INTENT_BUGREPORT_SCREENSHOT =
+ "android.intent.action.BUGREPORT_SCREENSHOT";
static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT";
static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT";
static final String EXTRA_PID = "android.intent.extra.PID";
static final String EXTRA_MAX = "android.intent.extra.MAX";
static final String EXTRA_NAME = "android.intent.extra.NAME";
+ static final String EXTRA_TITLE = "android.intent.extra.TITLE";
+ static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
static final String EXTRA_ORIGINAL_INTENT = "android.intent.extra.ORIGINAL_INTENT";
private static final int MSG_SERVICE_COMMAND = 1;
private static final int MSG_POLL = 2;
+ private static final int MSG_DELAYED_SCREENSHOT = 3;
+ private static final int MSG_SCREENSHOT_REQUEST = 4;
+ private static final int MSG_SCREENSHOT_RESPONSE = 5;
+
+ /**
+ * Delay before a screenshot is taken.
+ * <p>
+ * Should be at least 3 seconds, otherwise its toast might show up in the screenshot.
+ */
+ static final int SCREENSHOT_DELAY_SECONDS = 3;
/** Polling frequency, in milliseconds. */
- static final long POLLING_FREQUENCY = 2000;
+ static final long POLLING_FREQUENCY = 2 * DateUtils.SECOND_IN_MILLIS;
/** How long (in ms) a dumpstate process will be monitored if it didn't show progress. */
private static final long INACTIVITY_TIMEOUT = 3 * DateUtils.MINUTE_IN_MILLIS;
@@ -124,35 +157,62 @@
private static final String DUMPSTATE_PREFIX = "dumpstate.";
private static final String PROGRESS_SUFFIX = ".progress";
private static final String MAX_SUFFIX = ".max";
+ private static final String NAME_SUFFIX = ".name";
- /** System property (and value) used for stop dumpstate. */
+ /** System property (and value) used to stop dumpstate. */
+ // TODO: should call ActiveManager API instead
private static final String CTL_STOP = "ctl.stop";
private static final String BUGREPORT_SERVICE = "bugreportplus";
+ /**
+ * Directory on Shell's data storage where screenshots will be stored.
+ * <p>
+ * Must be a path supported by its FileProvider.
+ */
+ private static final String SCREENSHOT_DIR = "bugreports";
+
/** Managed dumpstate processes (keyed by pid) */
private final SparseArray<BugreportInfo> mProcesses = new SparseArray<>();
- private Looper mServiceLooper;
- private ServiceHandler mServiceHandler;
+ private Context mContext;
+ private ServiceHandler mMainHandler;
+ private ScreenshotHandler mScreenshotHandler;
+
+ private final BugreportInfoDialog mInfoDialog = new BugreportInfoDialog();
+
+ private File mScreenshotsDir;
+
+ /**
+ * Flag indicating whether a screenshot is being taken.
+ * <p>
+ * This is the only state that is shared between the 2 handlers and hence must have synchronized
+ * access.
+ */
+ private boolean mTakingScreenshot;
@Override
public void onCreate() {
- HandlerThread thread = new HandlerThread("BugreportProgressServiceThread",
- Process.THREAD_PRIORITY_BACKGROUND);
- thread.start();
+ mContext = getApplicationContext();
+ mMainHandler = new ServiceHandler("BugreportProgressServiceMainThread");
+ mScreenshotHandler = new ScreenshotHandler("BugreportProgressServiceScreenshotThread");
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper);
+ mScreenshotsDir = new File(new ContextWrapper(mContext).getFilesDir(), SCREENSHOT_DIR);
+ if (!mScreenshotsDir.exists()) {
+ Log.i(TAG, "Creating directory " + mScreenshotsDir + " to store temporary screenshots");
+ if (!mScreenshotsDir.mkdir()) {
+ Log.w(TAG, "Could not create directory " + mScreenshotsDir);
+ }
+ }
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
// Handle it in a separate thread.
- Message msg = mServiceHandler.obtainMessage();
+ final Message msg = mMainHandler.obtainMessage();
msg.what = MSG_SERVICE_COMMAND;
msg.obj = intent;
- mServiceHandler.sendMessage(msg);
+ mMainHandler.sendMessage(msg);
}
// If service is killed it cannot be recreated because it would not know which
@@ -167,29 +227,31 @@
@Override
public void onDestroy() {
- mServiceLooper.quit();
+ mMainHandler.getLooper().quit();
+ mScreenshotHandler.getLooper().quit();
super.onDestroy();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- synchronized (mProcesses) {
- final int size = mProcesses.size();
- if (size == 0) {
- writer.printf("No monitored processes");
- return;
- }
- writer.printf("Monitored dumpstate processes\n");
- writer.printf("-----------------------------\n");
- for (int i = 0; i < size; i++) {
- writer.printf("%s\n", mProcesses.valueAt(i));
- }
+ final int size = mProcesses.size();
+ if (size == 0) {
+ writer.printf("No monitored processes");
+ return;
+ }
+ writer.printf("Monitored dumpstate processes\n");
+ writer.printf("-----------------------------\n");
+ for (int i = 0; i < size; i++) {
+ writer.printf("%s\n", mProcesses.valueAt(i));
}
}
+ /**
+ * Main thread used to handle all requests but taking screenshots.
+ */
private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
+ public ServiceHandler(String name) {
+ super(newLooper(name));
}
@Override
@@ -199,6 +261,16 @@
return;
}
+ if (msg.what == MSG_DELAYED_SCREENSHOT) {
+ takeScreenshot(msg.arg1, msg.arg2);
+ return;
+ }
+
+ if (msg.what == MSG_SCREENSHOT_RESPONSE) {
+ handleScreenshotResponse(msg);
+ return;
+ }
+
if (msg.what != MSG_SERVICE_COMMAND) {
// Sanity check.
Log.e(TAG, "Invalid message type: " + msg.what);
@@ -242,6 +314,12 @@
}
onBugreportFinished(pid, intent);
break;
+ case INTENT_BUGREPORT_INFO_LAUNCH:
+ launchBugreportInfoDialog(pid);
+ break;
+ case INTENT_BUGREPORT_SCREENSHOT:
+ takeScreenshot(pid, true);
+ break;
case INTENT_BUGREPORT_SHARE:
shareBugreport(pid);
break;
@@ -266,6 +344,32 @@
}
/**
+ * Separate thread used only to take screenshots so it doesn't block the main thread.
+ */
+ private final class ScreenshotHandler extends Handler {
+ public ScreenshotHandler(String name) {
+ super(newLooper(name));
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what != MSG_SCREENSHOT_REQUEST) {
+ Log.e(TAG, "Invalid message type: " + msg.what);
+ return;
+ }
+ handleScreenshotRequest(msg);
+ }
+ }
+
+ private BugreportInfo getInfo(int pid) {
+ final BugreportInfo info = mProcesses.get(pid);
+ if (info == null) {
+ Log.w(TAG, "Not monitoring process with PID " + pid);
+ }
+ return info;
+ }
+
+ /**
* Creates the {@link BugreportInfo} for a process and issue a system notification to
* indicate its progress.
*
@@ -284,14 +388,14 @@
return false;
}
- final BugreportInfo info = new BugreportInfo(getApplicationContext(), pid, name, max);
- synchronized (mProcesses) {
- if (mProcesses.indexOfKey(pid) >= 0) {
- Log.w(TAG, "PID " + pid + " already watched");
- } else {
- mProcesses.put(info.pid, info);
- }
+ final BugreportInfo info = new BugreportInfo(mContext, pid, name, max);
+ if (mProcesses.indexOfKey(pid) >= 0) {
+ Log.w(TAG, "PID " + pid + " already watched");
+ } else {
+ mProcesses.put(info.pid, info);
}
+ // Take initial screenshot.
+ takeScreenshot(pid, false);
updateProgress(info);
return true;
}
@@ -305,19 +409,35 @@
return;
}
- final Context context = getApplicationContext();
final NumberFormat nf = NumberFormat.getPercentInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
final String percentText = nf.format((double) info.progress / info.max);
- final Action cancelAction = new Action.Builder(null, context.getString(
- com.android.internal.R.string.cancel), newCancelIntent(context, info)).build();
+ final Action cancelAction = new Action.Builder(null, mContext.getString(
+ com.android.internal.R.string.cancel), newCancelIntent(mContext, info)).build();
+ final Intent infoIntent = new Intent(mContext, BugreportProgressService.class);
+ infoIntent.setAction(INTENT_BUGREPORT_INFO_LAUNCH);
+ infoIntent.putExtra(EXTRA_PID, info.pid);
+ final Action infoAction = new Action.Builder(null,
+ mContext.getString(R.string.bugreport_info_action),
+ PendingIntent.getService(mContext, info.pid, infoIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT)).build();
+ final Intent screenshotIntent = new Intent(mContext, BugreportProgressService.class);
+ screenshotIntent.setAction(INTENT_BUGREPORT_SCREENSHOT);
+ screenshotIntent.putExtra(EXTRA_PID, info.pid);
+ PendingIntent screenshotPendingIntent = mTakingScreenshot ? null : PendingIntent
+ .getService(mContext, info.pid, screenshotIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ final Action screenshotAction = new Action.Builder(null,
+ mContext.getString(R.string.bugreport_screenshot_action),
+ screenshotPendingIntent).build();
- final String title = context.getString(R.string.bugreport_in_progress_title);
+ final String title = mContext.getString(R.string.bugreport_in_progress_title);
+
final String name =
- info.name != null ? info.name : context.getString(R.string.bugreport_unnamed);
+ info.name != null ? info.name : mContext.getString(R.string.bugreport_unnamed);
- final Notification notification = new Notification.Builder(context)
+ final Notification notification = new Notification.Builder(mContext)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setContentTitle(title)
.setTicker(title)
@@ -326,12 +446,19 @@
.setProgress(info.max, info.progress, false)
.setOngoing(true)
.setLocalOnly(true)
- .setColor(context.getColor(
+ .setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
+ .addAction(infoAction)
+ .addAction(screenshotAction)
.addAction(cancelAction)
.build();
- NotificationManager.from(context).notify(TAG, info.pid, notification);
+ if (info.finished) {
+ Log.w(TAG, "Not sending progress notification because bugreport has finished already ("
+ + info + ")");
+ return;
+ }
+ NotificationManager.from(mContext).notify(TAG, info.pid, notification);
}
/**
@@ -341,31 +468,35 @@
final Intent intent = new Intent(INTENT_BUGREPORT_CANCEL);
intent.setClass(context, BugreportProgressService.class);
intent.putExtra(EXTRA_PID, info.pid);
- return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ return PendingIntent.getService(context, info.pid, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* Finalizes the progress on a given bugreport and cancel its notification.
*/
private void stopProgress(int pid) {
- synchronized (mProcesses) {
- if (mProcesses.indexOfKey(pid) < 0) {
- Log.w(TAG, "PID not watched: " + pid);
- } else {
- mProcesses.remove(pid);
- }
- stopSelfWhenDone();
+ if (mProcesses.indexOfKey(pid) < 0) {
+ Log.w(TAG, "PID not watched: " + pid);
+ } else {
+ mProcesses.remove(pid);
}
- if (DEBUG) Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
- NotificationManager.from(getApplicationContext()).cancel(TAG, pid);
+ stopSelfWhenDone();
+ Log.v(TAG, "stopProgress(" + pid + "): cancel notification");
+ NotificationManager.from(mContext).cancel(TAG, pid);
}
/**
* Cancels a bugreport upon user's request.
*/
private void cancel(int pid) {
- Log.i(TAG, "Cancelling PID " + pid + " on user's request");
- SystemProperties.set(CTL_STOP, BUGREPORT_SERVICE);
+ Log.v(TAG, "cancel: pid=" + pid);
+ final BugreportInfo info = getInfo(pid);
+ if (info != null && !info.finished) {
+ Log.i(TAG, "Cancelling bugreport service (pid=" + pid + ") on user's request");
+ setSystemProperty(CTL_STOP, BUGREPORT_SERVICE);
+ deleteScreenshots(info);
+ }
stopProgress(pid);
}
@@ -375,54 +506,188 @@
* @return whether it should keep polling.
*/
private boolean pollProgress() {
- synchronized (mProcesses) {
- final int total = mProcesses.size();
- if (total == 0) {
- Log.d(TAG, "No process to poll progress.");
+ final int total = mProcesses.size();
+ if (total == 0) {
+ Log.d(TAG, "No process to poll progress.");
+ }
+ int activeProcesses = 0;
+ for (int i = 0; i < total; i++) {
+ final int pid = mProcesses.keyAt(i);
+ final BugreportInfo info = mProcesses.valueAt(i);
+ if (info.finished) {
+ if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+ continue;
}
- int activeProcesses = 0;
- for (int i = 0; i < total; i++) {
- final int pid = mProcesses.keyAt(i);
+ activeProcesses++;
+ final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
+ final int progress = SystemProperties.getInt(progressKey, 0);
+ if (progress == 0) {
+ Log.v(TAG, "System property " + progressKey + " is not set yet");
+ }
+ final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
+ final boolean maxChanged = max > 0 && max != info.max;
+ final boolean progressChanged = progress > 0 && progress != info.progress;
+
+ if (progressChanged || maxChanged) {
+ if (progressChanged) {
+ if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
+ + info.progress + " to " + progress);
+ info.progress = progress;
+ }
+ if (maxChanged) {
+ Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
+ + " to " + max);
+ info.max = max;
+ }
+ info.lastUpdate = System.currentTimeMillis();
+ updateProgress(info);
+ } else {
+ long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
+ if (inactiveTime >= INACTIVITY_TIMEOUT) {
+ Log.w(TAG, "No progress update for process " + pid + " since "
+ + info.getFormattedLastUpdate());
+ stopProgress(info.pid);
+ }
+ }
+ }
+ if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
+ return activeProcesses > 0;
+ }
+
+ /**
+ * Fetches a {@link BugreportInfo} for a given process and launches a dialog where the user can
+ * change its values.
+ */
+ private void launchBugreportInfoDialog(int pid) {
+ // Copy values so it doesn't lock mProcesses while UI is being updated
+ final String name, title, description;
+ final BugreportInfo info = getInfo(pid);
+ if (info == null) {
+ return;
+ }
+ name = info.name;
+ title = info.title;
+ description = info.description;
+
+ collapseNotificationBar();
+ mInfoDialog.initialize(mContext, pid, name, title, description);
+ }
+
+ /**
+ * Starting point for taking a screenshot.
+ * <p>
+ * If {@code delayed} is set, it first display a toast message and waits
+ * {@link #SCREENSHOT_DELAY_SECONDS} seconds before taking it, otherwise it takes the screenshot
+ * right away.
+ * <p>
+ * Typical usage is delaying when taken from the notification action, and taking it right away
+ * upon receiving a {@link #INTENT_BUGREPORT_STARTED}.
+ */
+ private void takeScreenshot(int pid, boolean delayed) {
+ setTakingScreenshot(true);
+ if (delayed) {
+ collapseNotificationBar();
+ final String msg = mContext.getResources()
+ .getQuantityString(com.android.internal.R.plurals.bugreport_countdown,
+ SCREENSHOT_DELAY_SECONDS, SCREENSHOT_DELAY_SECONDS);
+ Log.i(TAG, msg);
+ // Show a toast just once, otherwise it might be captured in the screenshot.
+ Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
+
+ takeScreenshot(pid, SCREENSHOT_DELAY_SECONDS);
+ } else {
+ takeScreenshot(pid, 0);
+ }
+ }
+
+ /**
+ * Takes a screenshot after {@code delay} seconds.
+ */
+ private void takeScreenshot(int pid, int delay) {
+ if (delay > 0) {
+ Log.d(TAG, "Taking screenshot for " + pid + " in " + delay + " seconds");
+ final Message msg = mMainHandler.obtainMessage();
+ msg.what = MSG_DELAYED_SCREENSHOT;
+ msg.arg1 = pid;
+ msg.arg2 = delay - 1;
+ mMainHandler.sendMessageDelayed(msg, DateUtils.SECOND_IN_MILLIS);
+ return;
+ }
+
+ // It's time to take the screenshot: let the proper thread handle it
+ final BugreportInfo info = getInfo(pid);
+ if (info == null) {
+ return;
+ }
+ final String screenshotPath =
+ new File(mScreenshotsDir, info.getPathNextScreenshot()).getAbsolutePath();
+
+ final Message requestMsg = new Message();
+ requestMsg.what = MSG_SCREENSHOT_REQUEST;
+ requestMsg.arg1 = pid;
+ requestMsg.obj = screenshotPath;
+ mScreenshotHandler.sendMessage(requestMsg);
+ }
+
+ /**
+ * Sets the internal {@code mTakingScreenshot} state and updates all notifications so their
+ * SCREENSHOT button is enabled or disabled accordingly.
+ */
+ private void setTakingScreenshot(boolean flag) {
+ synchronized (BugreportProgressService.this) {
+ mTakingScreenshot = flag;
+ for (int i = 0; i < mProcesses.size(); i++) {
final BugreportInfo info = mProcesses.valueAt(i);
if (info.finished) {
- if (DEBUG) Log.v(TAG, "Skipping finished process " + pid);
+ Log.d(TAG, "Not updating progress because share notification was already sent");
continue;
}
- activeProcesses++;
- final String progressKey = DUMPSTATE_PREFIX + pid + PROGRESS_SUFFIX;
- final int progress = SystemProperties.getInt(progressKey, 0);
- if (progress == 0) {
- Log.v(TAG, "System property " + progressKey + " is not set yet");
- continue;
- }
- final int max = SystemProperties.getInt(DUMPSTATE_PREFIX + pid + MAX_SUFFIX, 0);
- final boolean maxChanged = max > 0 && max != info.max;
- final boolean progressChanged = progress > 0 && progress != info.progress;
-
- if (progressChanged || maxChanged) {
- if (progressChanged) {
- if (DEBUG) Log.v(TAG, "Updating progress for PID " + pid + " from "
- + info.progress + " to " + progress);
- info.progress = progress;
- }
- if (maxChanged) {
- Log.i(TAG, "Updating max progress for PID " + pid + " from " + info.max
- + " to " + max);
- info.max = max;
- }
- info.lastUpdate = System.currentTimeMillis();
- updateProgress(info);
- } else {
- long inactiveTime = System.currentTimeMillis() - info.lastUpdate;
- if (inactiveTime >= INACTIVITY_TIMEOUT) {
- Log.w(TAG, "No progress update for process " + pid + " since "
- + info.getFormattedLastUpdate());
- stopProgress(info.pid);
- }
- }
+ updateProgress(info);
}
- if (DEBUG) Log.v(TAG, "pollProgress() total=" + total + ", actives=" + activeProcesses);
- return activeProcesses > 0;
+ }
+ }
+
+ private void handleScreenshotRequest(Message requestMsg) {
+ String screenshotFile = (String) requestMsg.obj;
+ boolean taken = takeScreenshot(mContext, screenshotFile);
+ setTakingScreenshot(false);
+
+ final Message resultMsg = new Message();
+ resultMsg.what = MSG_SCREENSHOT_RESPONSE;
+ resultMsg.arg1 = requestMsg.arg1;
+ resultMsg.arg2 = taken ? 1 : 0;
+ resultMsg.obj = screenshotFile;
+ mMainHandler.sendMessage(resultMsg);
+ }
+
+ private void handleScreenshotResponse(Message resultMsg) {
+ final boolean taken = resultMsg.arg2 != 0;
+ final BugreportInfo info = getInfo(resultMsg.arg1);
+ if (info == null) {
+ return;
+ }
+ final File screenshotFile = new File((String) resultMsg.obj);
+
+ final int msgId;
+ if (taken) {
+ info.addScreenshot(screenshotFile);
+ msgId = R.string.bugreport_screenshot_taken;
+ } else {
+ // TODO: try again using Framework APIs instead of relying on screencap.
+ msgId = R.string.bugreport_screenshot_failed;
+ }
+ final String msg = mContext.getString(msgId);
+ Log.d(TAG, msg);
+ Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
+ }
+
+ /**
+ * Deletes all screenshots taken for a given bugreport.
+ */
+ private void deleteScreenshots(BugreportInfo info) {
+ for (File file : info.screenshotFiles) {
+ Log.i(TAG, "Deleting screenshot file " + file);
+ file.delete();
}
}
@@ -430,34 +695,37 @@
* Finishes the service when it's not monitoring any more processes.
*/
private void stopSelfWhenDone() {
- synchronized (mProcesses) {
- if (mProcesses.size() > 0) {
- if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
- return;
- }
- Log.v(TAG, "No more pids to handle, shutting down");
- stopSelf();
+ if (mProcesses.size() > 0) {
+ if (DEBUG) Log.v(TAG, "Staying alive, waiting for pids " + mProcesses);
+ return;
}
+ Log.v(TAG, "No more pids to handle, shutting down");
+ stopSelf();
}
+ /**
+ * Handles the BUGREPORT_FINISHED intent sent by {@code dumpstate}.
+ */
private void onBugreportFinished(int pid, Intent intent) {
- final Context context = getApplicationContext();
- BugreportInfo info;
- synchronized (mProcesses) {
- info = mProcesses.get(pid);
- if (info == null) {
- // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED
- Log.v(TAG, "Creating info for untracked pid " + pid);
- info = new BugreportInfo(context, pid);
- mProcesses.put(pid, info);
- }
- info.bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
- info.screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+ mInfoDialog.onBugreportFinished(pid);
+ BugreportInfo info = getInfo(pid);
+ if (info == null) {
+ // Happens when BUGREPORT_FINISHED was received without a BUGREPORT_STARTED first.
+ Log.v(TAG, "Creating info for untracked pid " + pid);
+ info = new BugreportInfo(mContext, pid);
+ mProcesses.put(pid, info);
}
+ info.renameScreenshots(mScreenshotsDir);
+ info.bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT);
+ final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
+ if (screenshot != null) {
+ info.addScreenshot(screenshot);
+ }
+ info.finished = true;
- final Configuration conf = context.getResources().getConfiguration();
+ final Configuration conf = mContext.getResources().getConfiguration();
if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
- triggerLocalNotification(context, info);
+ triggerLocalNotification(mContext, info);
}
}
@@ -467,11 +735,11 @@
* (usually by triggering it on another connected device); we don't need to display the
* notification in this case.
*/
- private static void triggerLocalNotification(final Context context, final BugreportInfo info) {
+ private void triggerLocalNotification(final Context context, final BugreportInfo info) {
if (!info.bugreportFile.exists() || !info.bugreportFile.canRead()) {
Log.e(TAG, "Could not read bugreport file " + info.bugreportFile);
- Toast.makeText(context, context.getString(R.string.bugreport_unreadable_text),
- Toast.LENGTH_LONG).show();
+ Toast.makeText(context, R.string.bugreport_unreadable_text, Toast.LENGTH_LONG).show();
+ stopProgress(info.pid);
return;
}
@@ -494,25 +762,36 @@
/**
* Build {@link Intent} that can be used to share the given bugreport.
*/
- private static Intent buildSendIntent(Context context, Uri bugreportUri, Uri screenshotUri) {
+ private static Intent buildSendIntent(Context context, BugreportInfo info) {
+ // Files are kept on private storage, so turn into Uris that we can
+ // grant temporary permissions for.
+ final Uri bugreportUri = getUri(context, info.bugreportFile);
+
final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
final String mimeType = "application/vnd.android.bugreport";
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(mimeType);
- intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
+ final String subject = info.title != null ? info.title : bugreportUri.getLastPathSegment();
+ intent.putExtra(Intent.EXTRA_SUBJECT, subject);
// EXTRA_TEXT should be an ArrayList, but some clients are expecting a single String.
// So, to avoid an exception on Intent.migrateExtraStreamToClipData(), we need to manually
// create the ClipData object with the attachments URIs.
- String messageBody = String.format("Build info: %s\nSerial number:%s",
- SystemProperties.get("ro.build.description"), SystemProperties.get("ro.serialno"));
- intent.putExtra(Intent.EXTRA_TEXT, messageBody);
+ final StringBuilder messageBody = new StringBuilder("Build info: ")
+ .append(SystemProperties.get("ro.build.description"))
+ .append("\nSerial number: ")
+ .append(SystemProperties.get("ro.serialno"));
+ if (!TextUtils.isEmpty(info.description)) {
+ messageBody.append("\nDescription: ").append(info.description);
+ }
+ intent.putExtra(Intent.EXTRA_TEXT, messageBody.toString());
final ClipData clipData = new ClipData(null, new String[] { mimeType },
new ClipData.Item(null, null, null, bugreportUri));
final ArrayList<Uri> attachments = Lists.newArrayList(bugreportUri);
- if (screenshotUri != null) {
+ for (File screenshot : info.screenshotFiles) {
+ final Uri screenshotUri = getUri(context, screenshot);
clipData.addItem(new ClipData.Item(null, null, null, screenshotUri));
attachments.add(screenshotUri);
}
@@ -532,34 +811,28 @@
* intent, but issuing a warning dialog the first time.
*/
private void shareBugreport(int pid) {
- final Context context = getApplicationContext();
- final BugreportInfo info;
- synchronized (mProcesses) {
- info = mProcesses.get(pid);
- if (info == null) {
- // Should not happen, so log if it does...
- Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses);
- return;
- }
+ final BugreportInfo info = getInfo(pid);
+ if (info == null) {
+ // Should not happen, so log if it does...
+ Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses);
+ return;
}
- // Files are kept on private storage, so turn into Uris that we can
- // grant temporary permissions for.
- final Uri bugreportUri = getUri(context, info.bugreportFile);
- final Uri screenshotUri = getUri(context, info.screenshotFile);
- final Intent sendIntent = buildSendIntent(context, bugreportUri, screenshotUri);
+ addDetailsToZipFile(info);
+
+ final Intent sendIntent = buildSendIntent(mContext, info);
final Intent notifIntent;
// Send through warning dialog by default
- if (getWarningState(context, STATE_SHOW) == STATE_SHOW) {
- notifIntent = buildWarningIntent(context, sendIntent);
+ if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+ notifIntent = buildWarningIntent(mContext, sendIntent);
} else {
notifIntent = sendIntent;
}
notifIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Send the share intent...
- context.startActivity(notifIntent);
+ mContext.startActivity(notifIntent);
// ... and stop watching this process.
stopProgress(pid);
@@ -580,13 +853,17 @@
.setContentTitle(title)
.setTicker(title)
.setContentText(context.getString(R.string.bugreport_finished_text))
- .setContentIntent(PendingIntent.getService(context, 0, shareIntent,
- PendingIntent.FLAG_CANCEL_CURRENT))
+ .setContentIntent(PendingIntent.getService(context, info.pid, shareIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT))
.setDeleteIntent(newCancelIntent(context, info))
.setLocalOnly(true)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color));
+ if (!TextUtils.isEmpty(info.name)) {
+ builder.setContentInfo(info.name);
+ }
+
NotificationManager.from(context).notify(TAG, info.pid, builder.build());
}
@@ -598,7 +875,7 @@
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- info.bugreportFile = zipBugreport(info.bugreportFile);
+ zipBugreport(info);
sendBugreportNotification(context, info);
return null;
}
@@ -609,35 +886,92 @@
* Zips a bugreport file, returning the path to the new file (or to the
* original in case of failure).
*/
- private static File zipBugreport(File bugreportFile) {
- String bugreportPath = bugreportFile.getAbsolutePath();
- String zippedPath = bugreportPath.replace(".txt", ".zip");
+ private static void zipBugreport(BugreportInfo info) {
+ final String bugreportPath = info.bugreportFile.getAbsolutePath();
+ final String zippedPath = bugreportPath.replace(".txt", ".zip");
Log.v(TAG, "zipping " + bugreportPath + " as " + zippedPath);
- File bugreportZippedFile = new File(zippedPath);
- try (InputStream is = new FileInputStream(bugreportFile);
+ final File bugreportZippedFile = new File(zippedPath);
+ try (InputStream is = new FileInputStream(info.bugreportFile);
ZipOutputStream zos = new ZipOutputStream(
new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) {
- ZipEntry entry = new ZipEntry(bugreportFile.getName());
- entry.setTime(bugreportFile.lastModified());
- zos.putNextEntry(entry);
- int totalBytes = Streams.copy(is, zos);
- Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes");
- zos.closeEntry();
- // Delete old file;
- boolean deleted = bugreportFile.delete();
+ addEntry(zos, info.bugreportFile.getName(), is);
+ // Delete old file
+ final boolean deleted = info.bugreportFile.delete();
if (deleted) {
Log.v(TAG, "deleted original bugreport (" + bugreportPath + ")");
} else {
Log.e(TAG, "could not delete original bugreport (" + bugreportPath + ")");
}
- return bugreportZippedFile;
+ info.bugreportFile = bugreportZippedFile;
} catch (IOException e) {
Log.e(TAG, "exception zipping file " + zippedPath, e);
- return bugreportFile; // Return original.
}
}
/**
+ * Adds the user-provided info into the bugreport zip file.
+ * <p>
+ * If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
+ * description will be saved on {@code description.txt}.
+ */
+ private void addDetailsToZipFile(BugreportInfo info) {
+ // It's not possible to add a new entry into an existing file, so we need to create a new
+ // zip, copy all entries, then rename it.
+ final File dir = info.bugreportFile.getParentFile();
+ final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
+ Log.d(TAG, "Writing temporary zip file (" + tmpZip + ")");
+ try (ZipFile oldZip = new ZipFile(info.bugreportFile);
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpZip))) {
+
+ // First copy contents from original zip.
+ Enumeration<? extends ZipEntry> entries = oldZip.entries();
+ while (entries.hasMoreElements()) {
+ final ZipEntry entry = entries.nextElement();
+ final String entryName = entry.getName();
+ if (!entry.isDirectory()) {
+ addEntry(zos, entryName, entry.getTime(), oldZip.getInputStream(entry));
+ } else {
+ Log.w(TAG, "skipping directory entry: " + entryName);
+ }
+ }
+
+ // Then add the user-provided info.
+ addEntry(zos, "title.txt", info.title);
+ addEntry(zos, "description.txt", info.description);
+ } catch (IOException e) {
+ Log.e(TAG, "exception zipping file " + tmpZip, e);
+ return;
+ }
+
+ if (!tmpZip.renameTo(info.bugreportFile)) {
+ Log.e(TAG, "Could not rename " + tmpZip + " to " + info.bugreportFile);
+ }
+ }
+
+ private static void addEntry(ZipOutputStream zos, String entry, String text)
+ throws IOException {
+ if (DEBUG) Log.v(TAG, "adding entry '" + entry + "': " + text);
+ if (!TextUtils.isEmpty(text)) {
+ addEntry(zos, entry, new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)));
+ }
+ }
+
+ private static void addEntry(ZipOutputStream zos, String entryName, InputStream is)
+ throws IOException {
+ addEntry(zos, entryName, System.currentTimeMillis(), is);
+ }
+
+ private static void addEntry(ZipOutputStream zos, String entryName, long timestamp,
+ InputStream is) throws IOException {
+ final ZipEntry entry = new ZipEntry(entryName);
+ entry.setTime(timestamp);
+ zos.putNextEntry(entry);
+ final int totalBytes = Streams.copy(is, zos);
+ if (DEBUG) Log.v(TAG, "size of '" + entryName + "' entry: " + totalBytes + " bytes");
+ zos.closeEntry();
+ }
+
+ /**
* Find the best matching {@link Account} based on build properties.
*/
private static Account findSendToAccount(Context context) {
@@ -684,6 +1018,262 @@
}
}
+ private static boolean setSystemProperty(String key, String value) {
+ try {
+ if (DEBUG) Log.v(TAG, "Setting system property" + key + " to " + value);
+ SystemProperties.set(key, value);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Could not set property " + key + " to " + value, e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Updates the system property used by {@code dumpstate} to rename the final bugreport files.
+ */
+ private boolean setBugreportNameProperty(int pid, String name) {
+ Log.d(TAG, "Updating bugreport name to " + name);
+ final String key = DUMPSTATE_PREFIX + pid + NAME_SUFFIX;
+ return setSystemProperty(key, name);
+ }
+
+ /**
+ * Updates the user-provided details of a bugreport.
+ */
+ private void updateBugreportInfo(int pid, String name, String title, String description) {
+ final BugreportInfo info = getInfo(pid);
+ if (info == null) {
+ return;
+ }
+ info.title = title;
+ info.description = description;
+ if (name != null && !info.name.equals(name)) {
+ info.name = name;
+ updateProgress(info);
+ }
+ }
+
+ private void collapseNotificationBar() {
+ sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+ }
+
+ private static Looper newLooper(String name) {
+ final HandlerThread thread = new HandlerThread(name, THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ return thread.getLooper();
+ }
+
+ /**
+ * Takes a screenshot and save it to the given location.
+ */
+ private static boolean takeScreenshot(Context context, String screenshotFile) {
+ ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
+ .vibrate(150);
+ final ProcessBuilder screencap = new ProcessBuilder()
+ .command("/system/bin/screencap", "-p", screenshotFile);
+ Log.d(TAG, "Taking screenshot using " + screencap.command());
+ try {
+ final int exitValue = screencap.start().waitFor();
+ if (exitValue == 0) {
+ return true;
+ }
+ Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
+ } catch (IOException e) {
+ Log.e(TAG, "screencap (" + screencap.command() + ") failed", e);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Thread interrupted while screencap still running");
+ Thread.currentThread().interrupt();
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a character is valid on bugreport names.
+ */
+ @VisibleForTesting
+ static boolean isValid(char c) {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')
+ || c == '_' || c == '-';
+ }
+
+ /**
+ * Helper class encapsulating the UI elements and logic used to display a dialog where user
+ * can change the details of a bugreport.
+ */
+ private final class BugreportInfoDialog {
+ private EditText mInfoName;
+ private EditText mInfoTitle;
+ private EditText mInfoDescription;
+ private AlertDialog mDialog;
+ private Button mOkButton;
+ private int mPid;
+
+ /**
+ * Last "committed" value of the bugreport name.
+ * <p>
+ * Once initially set, it's only updated when user clicks the OK button.
+ */
+ private String mSavedName;
+
+ /**
+ * Last value of the bugreport name as entered by the user.
+ * <p>
+ * Every time it's changed the equivalent system property is changed as well, but if the
+ * user clicks CANCEL, the old value (stored on {@code mSavedName} is restored.
+ * <p>
+ * This logic handles the corner-case scenario where {@code dumpstate} finishes after the
+ * user changed the name but didn't clicked OK yet (for example, because the user is typing
+ * the description). The only drawback is that if the user changes the name while
+ * {@code dumpstate} is running but clicks CANCEL after it finishes, then the final name
+ * will be the one that has been canceled. But when {@code dumpstate} finishes the {code
+ * name} UI is disabled and the old name restored anyways, so the user will be "alerted" of
+ * such drawback.
+ */
+ private String mTempName;
+
+ /**
+ * Sets its internal state and displays the dialog.
+ */
+ private void initialize(Context context, int pid, String name, String title,
+ String description) {
+ // First initializes singleton.
+ if (mDialog == null) {
+ @SuppressLint("InflateParams")
+ // It's ok pass null ViewRoot on AlertDialogs.
+ final View view = View.inflate(context, R.layout.dialog_bugreport_info, null);
+
+ mInfoName = (EditText) view.findViewById(R.id.name);
+ mInfoTitle = (EditText) view.findViewById(R.id.title);
+ mInfoDescription = (EditText) view.findViewById(R.id.description);
+
+ mInfoName.setOnFocusChangeListener(new OnFocusChangeListener() {
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ return;
+ }
+ sanitizeName();
+ }
+ });
+
+ mDialog = new AlertDialog.Builder(context)
+ .setView(view)
+ .setTitle(context.getString(R.string.bugreport_info_dialog_title))
+ .setCancelable(false)
+ .setPositiveButton(context.getString(com.android.internal.R.string.ok),
+ null)
+ .setNegativeButton(context.getString(com.android.internal.R.string.cancel),
+ new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int id)
+ {
+ if (!mTempName.equals(mSavedName)) {
+ // Must restore dumpstate's name since it was changed
+ // before user clicked OK.
+ setBugreportNameProperty(mPid, mSavedName);
+ }
+ }
+ })
+ .create();
+
+ mDialog.getWindow().setAttributes(
+ new WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG));
+
+ }
+
+ // Then set fields.
+ mSavedName = mTempName = name;
+ mPid = pid;
+ if (!TextUtils.isEmpty(name)) {
+ mInfoName.setText(name);
+ }
+ if (!TextUtils.isEmpty(title)) {
+ mInfoTitle.setText(title);
+ }
+ if (!TextUtils.isEmpty(description)) {
+ mInfoDescription.setText(description);
+ }
+
+ // And finally display it.
+ mDialog.show();
+
+ // TODO: in a traditional AlertDialog, when the positive button is clicked the
+ // dialog is always closed, but we need to validate the name first, so we need to
+ // get a reference to it, which is only available after it's displayed.
+ // It would be cleaner to use a regular dialog instead, but let's keep this
+ // workaround for now and change it later, when we add another button to take
+ // extra screenshots.
+ if (mOkButton == null) {
+ mOkButton = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
+ mOkButton.setOnClickListener(new View.OnClickListener() {
+
+ @Override
+ public void onClick(View view) {
+ sanitizeName();
+ final String name = mInfoName.getText().toString();
+ final String title = mInfoTitle.getText().toString();
+ final String description = mInfoDescription.getText().toString();
+
+ updateBugreportInfo(mPid, name, title, description);
+ mDialog.dismiss();
+ }
+ });
+ }
+ }
+
+ /**
+ * Sanitizes the user-provided value for the {@code name} field, automatically replacing
+ * invalid characters if necessary.
+ */
+ private void sanitizeName() {
+ String name = mInfoName.getText().toString();
+ if (name.equals(mTempName)) {
+ if (DEBUG) Log.v(TAG, "name didn't change, no need to sanitize: " + name);
+ return;
+ }
+ final StringBuilder safeName = new StringBuilder(name.length());
+ boolean changed = false;
+ for (int i = 0; i < name.length(); i++) {
+ final char c = name.charAt(i);
+ if (isValid(c)) {
+ safeName.append(c);
+ } else {
+ changed = true;
+ safeName.append('_');
+ }
+ }
+ if (changed) {
+ Log.v(TAG, "changed invalid name '" + name + "' to '" + safeName + "'");
+ name = safeName.toString();
+ mInfoName.setText(name);
+ }
+ mTempName = name;
+
+ // Must update system property for the cases where dumpstate finishes
+ // while the user is still entering other fields (like title or
+ // description)
+ setBugreportNameProperty(mPid, name);
+ }
+
+ /**
+ * Notifies the dialog that the bugreport has finished so it disables the {@code name}
+ * field.
+ * <p>Once the bugreport is finished dumpstate has already generated the final files, so
+ * changing the name would have no effect.
+ */
+ private void onBugreportFinished(int pid) {
+ if (mInfoName != null) {
+ mInfoName.setEnabled(false);
+ mInfoName.setText(mSavedName);
+ }
+ }
+
+ }
+
/**
* Information about a bugreport process while its in progress.
*/
@@ -704,6 +1294,18 @@
String name;
/**
+ * User-provided, one-line summary of the bug; when set, will be used as the subject
+ * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+ */
+ String title;
+
+ /**
+ * User-provided, detailed description of the bugreport; when set, will be added to the body
+ * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+ */
+ String description;
+
+ /**
* Maximum progress of the bugreport generation.
*/
int max;
@@ -724,9 +1326,9 @@
File bugreportFile;
/**
- * Path of the screenshot file.
+ * Path of the screenshot files.
*/
- File screenshotFile;
+ List<File> screenshotFiles = new ArrayList<>(1);
/**
* Whether dumpstate sent an intent informing it has finished.
@@ -734,6 +1336,11 @@
boolean finished;
/**
+ * Internal counter used to name screenshot files.
+ */
+ int screenshotCounter;
+
+ /**
* Constructor for tracked bugreports - typically called upon receiving BUGREPORT_STARTED.
*/
BugreportInfo(Context context, int pid, String name, int max) {
@@ -752,6 +1359,45 @@
this.finished = true;
}
+ /**
+ * Gets the name for next screenshot file.
+ */
+ String getPathNextScreenshot() {
+ screenshotCounter ++;
+ return "screenshot-" + pid + "-" + screenshotCounter + ".png";
+ }
+
+ /**
+ * Saves the location of a taken screenshot so it can be sent out at the end.
+ */
+ void addScreenshot(File screenshot) {
+ screenshotFiles.add(screenshot);
+ }
+
+ /**
+ * Rename all screenshots files so that they contain the user-generated name instead of pid.
+ */
+ void renameScreenshots(File screenshotDir) {
+ if (TextUtils.isEmpty(name)) {
+ return;
+ }
+ final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size());
+ for (File oldFile : screenshotFiles) {
+ final String oldName = oldFile.getName();
+ final String newName = oldName.replace(Integer.toString(pid), name);
+ final File newFile;
+ if (!newName.equals(oldName)) {
+ final File renamedFile = new File(screenshotDir, newName);
+ newFile = oldFile.renameTo(renamedFile) ? renamedFile : oldFile;
+ } else {
+ Log.w(TAG, "Name didn't change: " + oldName); // Shouldn't happen.
+ newFile = oldFile;
+ }
+ renamedFiles.add(newFile);
+ }
+ screenshotFiles = renamedFiles;
+ }
+
String getFormattedLastUpdate() {
return DateUtils.formatDateTime(context, lastUpdate,
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME);
@@ -761,7 +1407,8 @@
public String toString() {
final float percent = ((float) progress * 100 / max);
return "pid: " + pid + ", name: " + name + ", finished: " + finished
- + "\n\tfile: " + bugreportFile + "\n\tscreenshot: " + screenshotFile
+ + "\n\ttitle: " + title + "\n\tdescription: " + description
+ + "\n\tfile: " + bugreportFile + "\n\tscreenshots: " + screenshotFiles
+ "\n\tprogress: " + progress + "/" + max + "(" + percent + ")"
+ "\n\tlast_update: " + getFormattedLastUpdate();
}
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 62a37bc..1e0eaac 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -8,9 +8,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-# TODO: update and/or remove
LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator
-#LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator
LOCAL_PACKAGE_NAME := ShellTests
LOCAL_INSTRUMENTATION_FOR := Shell
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 1f4d749..d1a07ea 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -25,6 +25,7 @@
import static com.android.shell.BugreportProgressService.EXTRA_SCREENSHOT;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_FINISHED;
import static com.android.shell.BugreportProgressService.INTENT_BUGREPORT_STARTED;
+import static com.android.shell.BugreportProgressService.SCREENSHOT_DELAY_SECONDS;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
@@ -35,7 +36,10 @@
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
+import java.util.ArrayList;
import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -56,6 +60,8 @@
import android.support.test.uiautomator.UiObject;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.Log;
import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
@@ -94,7 +100,17 @@
private static final int PID = 42;
private static final String PROGRESS_PROPERTY = "dumpstate.42.progress";
private static final String MAX_PROPERTY = "dumpstate.42.max";
+ private static final String NAME_PROPERTY = "dumpstate.42.name";
private static final String NAME = "BUG, Y U NO REPORT?";
+ private static final String NEW_NAME = "Bug_Forrest_Bug";
+ private static final String TITLE = "Wimbugdom Champion 2015";
+
+ private static final String NO_DESCRIPTION = null;
+ private static final String NO_NAME = null;
+ private static final String NO_SCREENSHOT = null;
+ private static final String NO_TITLE = null;
+
+ private String mDescription;
private String mPlainTextPath;
private String mZipPath;
@@ -120,12 +136,20 @@
createTextFile(mScreenshotPath, SCREENSHOT_CONTENT);
createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT);
+ // Creates a multi-line description.
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i <= 20; i++) {
+ sb.append("All work and no play makes Shell a dull app!\n");
+ }
+ mDescription = sb.toString();
+
BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
}
- public void testFullWorkflow() throws Exception {
+ public void testProgress() throws Exception {
resetProperties();
sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
assertProgressNotification(NAME, "0.00%");
@@ -140,7 +164,161 @@
Bundle extras =
sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
+ assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE,
+ NAME, NO_TITLE, NO_DESCRIPTION, 1, true);
+
+ assertServiceNotRunning();
+ }
+
+ public void testProgress_takeExtraScreenshot() throws Exception {
+ resetProperties();
+ sendBugreportStarted(1000);
+
+ waitForScreenshotButtonEnabled(true);
+ takeScreenshot();
+ assertScreenshotButtonEnabled(false);
+ waitForScreenshotButtonEnabled(true);
+
+ Bundle extras =
+ sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE,
+ NAME, NO_TITLE, NO_DESCRIPTION, 2, true);
+
+ assertServiceNotRunning();
+ }
+
+ public void testProgress_changeDetailsInvalidInput() throws Exception {
+
+ resetProperties();
+ sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
+
+ DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+ // Check initial name.
+ String actualName = detailsUi.nameField.getText().toString();
+ assertEquals("Wrong value on field 'name'", NAME, actualName);
+
+ // Change name - it should have changed system property once focus is changed.
+ detailsUi.nameField.setText(NEW_NAME);
+ detailsUi.focusAwayFromName();
+ assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+
+ // Cancel the dialog to make sure property was restored.
+ detailsUi.clickCancel();
+ assertPropertyValue(NAME_PROPERTY, NAME);
+
+ // Now try to set an invalid name.
+ detailsUi.reOpen();
+ detailsUi.nameField.setText("/etc/passwd");
+ detailsUi.clickOk();
+ assertPropertyValue(NAME_PROPERTY, "_etc_passwd");
+
+ // Finally, make the real changes.
+ detailsUi.reOpen();
+ detailsUi.nameField.setText(NEW_NAME);
+ detailsUi.titleField.setText(TITLE);
+ detailsUi.descField.setText(mDescription);
+
+ detailsUi.clickOk();
+
+ assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+ assertProgressNotification(NEW_NAME, "0.00%");
+
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
+ mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
+ NEW_NAME, TITLE, mDescription, 1, true);
+
+ assertServiceNotRunning();
+ }
+
+ public void testProgress_changeDetailsPlainBugreport() throws Exception {
+ changeDetailsTest(true);
+ }
+
+ public void testProgress_changeDetailsZippedBugreport() throws Exception {
+ changeDetailsTest(false);
+ }
+
+ public void changeDetailsTest(boolean plainText) throws Exception {
+
+ resetProperties();
+ sendBugreportStarted(1000);
+ waitForScreenshotButtonEnabled(true);
+
+ DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+ // Check initial name.
+ String actualName = detailsUi.nameField.getText().toString();
+ assertEquals("Wrong value on field 'name'", NAME, actualName);
+
+ // Change fields.
+ detailsUi.reOpen();
+ detailsUi.nameField.setText(NEW_NAME);
+ detailsUi.titleField.setText(TITLE);
+ detailsUi.descField.setText(mDescription);
+
+ detailsUi.clickOk();
+
+ assertPropertyValue(NAME_PROPERTY, NEW_NAME);
+ assertProgressNotification(NEW_NAME, "0.00%");
+
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID,
+ plainText? mPlainTextPath : mZipPath, mScreenshotPath);
+ assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
+ NEW_NAME, TITLE, mDescription, 1, true);
+
+ assertServiceNotRunning();
+ }
+
+ /**
+ * Tests the scenario where the initial screenshot and dumpstate are finished while the user
+ * is changing the info in the details screen.
+ */
+ public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
+ bugreportFinishedWhileChangingDetailsTest(false);
+ }
+
+ /**
+ * Tests the scenario where dumpstate is finished while the user is changing the info in the
+ * details screen, but the initial screenshot finishes afterwards.
+ */
+ public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
+ bugreportFinishedWhileChangingDetailsTest(true);
+ }
+
+ private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
+ resetProperties();
+ sendBugreportStarted(1000);
+ if (waitScreenshot) {
+ waitForScreenshotButtonEnabled(true);
+ }
+
+ DetailsUi detailsUi = new DetailsUi(mUiBot);
+
+ // Finish the bugreport while user's still typing the name.
+ detailsUi.nameField.setText(NEW_NAME);
+ sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
+
+ // Wait until the share notification is received...
+ mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
+ // ...then close notification bar.
+ mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
+
+ // Make sure UI was updated properly.
+ assertFalse("didn't disable name on UI", detailsUi.nameField.isEnabled());
+ assertEquals("didn't revert name on UI", NAME, detailsUi.nameField.getText().toString());
+
+ // Finish changing other fields.
+ detailsUi.titleField.setText(TITLE);
+ detailsUi.descField.setText(mDescription);
+ detailsUi.clickOk();
+
+ // Finally, share bugreport.
+ Bundle extras = acceptBugreportAndGetSharedIntent();
+ assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE,
+ NAME, TITLE, mDescription, 1, waitScreenshot);
assertServiceNotRunning();
}
@@ -165,7 +343,7 @@
// Share the bugreport.
mUiBot.chooseActivity(UI_NAME);
Bundle extras = mListener.getExtras();
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
// Make sure it's hidden now.
int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
@@ -183,13 +361,13 @@
}
public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception {
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, null);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
}
public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception {
- Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, null);
- assertActionSendMultiple(extras, BUGREPORT_CONTENT, null);
+ Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT);
+ assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
}
private void cancelExistingNotifications() {
@@ -202,16 +380,20 @@
}
private void assertProgressNotification(String name, String percent) {
- // TODO: it current looks for 3 distinct objects, without taking advantage of their
+ // TODO: it currently looks for 3 distinct objects, without taking advantage of their
// relationship.
- String title = mContext.getString(R.string.bugreport_in_progress_title);
- Log.v(TAG, "Looking for progress notification title: '" + title+ "'");
- mUiBot.getNotification(title);
+ openProgressNotification();
Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'");
mUiBot.getObject(name);
mUiBot.getObject(percent);
}
+ private void openProgressNotification() {
+ String title = mContext.getString(R.string.bugreport_in_progress_title);
+ Log.v(TAG, "Looking for progress notification title: '" + title + "'");
+ mUiBot.getNotification(title);
+ }
+
void resetProperties() {
// TODO: call method to remove property instead
SystemProperties.set(PROGRESS_PROPERTY, "0");
@@ -221,7 +403,7 @@
/**
* Sends a "bugreport started" intent with the default values.
*/
- private void sendBugreportStarted(int max) {
+ private void sendBugreportStarted(int max) throws Exception {
Intent intent = new Intent(INTENT_BUGREPORT_STARTED);
intent.putExtra(EXTRA_PID, PID);
intent.putExtra(EXTRA_NAME, NAME);
@@ -270,7 +452,6 @@
/**
* Sends a "bugreport finished" intent.
- *
*/
private void sendBugreportFinished(Integer pid, String bugreportPath, String screenshotPath) {
Intent intent = new Intent(INTENT_BUGREPORT_FINISHED);
@@ -288,41 +469,102 @@
}
/**
- * Asserts the proper ACTION_SEND_MULTIPLE intent was sent.
+ * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
*/
private void assertActionSendMultiple(Bundle extras, String bugreportContent,
String screenshotContent) throws IOException {
+ assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE,
+ NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, false);
+ }
+
+ /**
+ * Asserts the proper {@link Intent#ACTION_SEND_MULTIPLE} intent was sent.
+ *
+ * @param extras extras received in the intent
+ * @param bugreportContent expected content in the bugreport file
+ * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any
+ * @param pid emulated dumpstate pid
+ * @param name expected subject
+ * @param name bugreport name as provided by the user (or received by dumpstate)
+ * @param title bugreport name as provided by the user
+ * @param description bugreport description as provided by the user
+ * @param numberScreenshots expected number of screenshots taken by Shell.
+ * @param renamedScreenshots whether the screenshots are expected to be renamed
+ */
+ private void assertActionSendMultiple(Bundle extras, String bugreportContent,
+ String screenshotContent, int pid, String subject,
+ String name, String title, String description,
+ int numberScreenshots, boolean renamedScreenshots) throws IOException {
String body = extras.getString(Intent.EXTRA_TEXT);
assertContainsRegex("missing build info",
SystemProperties.get("ro.build.description"), body);
assertContainsRegex("missing serial number",
SystemProperties.get("ro.serialno"), body);
+ if (description != null) {
+ assertContainsRegex("missing description", description, body);
+ }
- assertEquals("wrong subject", ZIP_FILE, extras.getString(Intent.EXTRA_SUBJECT));
+ assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT));
List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM);
- int expectedSize = screenshotContent != null ? 2 : 1;
+ int expectedNumberScreenshots = numberScreenshots;
+ if (screenshotContent != null) {
+ expectedNumberScreenshots ++; // Add screenshot received by dumpstate
+ }
+ int expectedSize = expectedNumberScreenshots + 1; // All screenshots plus the bugreport file
assertEquals("wrong number of attachments", expectedSize, attachments.size());
// Need to interact through all attachments, since order is not guaranteed.
- Uri zipUri = null, screenshotUri = null;
+ Uri zipUri = null;
+ List<Uri> screenshotUris = new ArrayList<>(expectedNumberScreenshots);
for (Uri attachment : attachments) {
if (attachment.getPath().endsWith(".zip")) {
zipUri = attachment;
}
if (attachment.getPath().endsWith(".png")) {
- screenshotUri = attachment;
+ screenshotUris.add(attachment);
}
}
assertNotNull("did not get .zip attachment", zipUri);
assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT);
-
- if (screenshotContent != null) {
- assertNotNull("did not get .png attachment", screenshotUri);
- assertContent(screenshotUri, SCREENSHOT_CONTENT);
- } else {
- assertNull("should not have .png attachment", screenshotUri);
+ if (!TextUtils.isEmpty(title)) {
+ assertZipContent(zipUri, "title.txt", title);
}
+ if (!TextUtils.isEmpty(description)) {
+ assertZipContent(zipUri, "description.txt", description);
+ }
+
+ // URI of the screenshot taken by dumpstate.
+ Uri externalScreenshotUri = null;
+ SortedSet<String> internalScreenshotNames = new TreeSet<>();
+ for (Uri screenshotUri : screenshotUris) {
+ String screenshotName = screenshotUri.getLastPathSegment();
+ if (screenshotName.endsWith(SCREENSHOT_FILE)) {
+ externalScreenshotUri = screenshotUri;
+ } else {
+ internalScreenshotNames.add(screenshotName);
+ }
+ }
+ // Check external screenshot
+ if (screenshotContent != null) {
+ assertNotNull("did not get .png attachment for external screenshot",
+ externalScreenshotUri);
+ assertContent(externalScreenshotUri, SCREENSHOT_CONTENT);
+ } else {
+ assertNull("should not have .png attachment for external screenshot",
+ externalScreenshotUri);
+ }
+ // Check internal screenshots.
+ SortedSet<String> expectedNames = new TreeSet<>();
+ for (int i = 1 ; i <= numberScreenshots; i++) {
+ String prefix = renamedScreenshots ? name : Integer.toString(pid);
+ String expectedName = "screenshot-" + prefix + "-" + i + ".png";
+ expectedNames.add(expectedName);
+ }
+ // Ideally we should use MoreAsserts, but the error message in case of failure is not
+ // really useful.
+ assertEquals("wrong names for internal screenshots",
+ expectedNames, internalScreenshotNames);
}
private void assertContent(Uri uri, String expectedContent) throws IOException {
@@ -355,6 +597,11 @@
fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
}
+ private void assertPropertyValue(String key, String expectedValue) {
+ String actualValue = SystemProperties.get(key);
+ assertEquals("Wrong value for property '" + key + "'", expectedValue, actualValue);
+ }
+
private void assertServiceNotRunning() {
String service = BugreportProgressService.class.getName();
assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
@@ -402,4 +649,96 @@
Log.v(TAG, "Path for '" + file + "': " + path);
return path;
}
+
+ /**
+ * Gets the notification button used to take a screenshot.
+ */
+ private UiObject getScreenshotButton() {
+ openProgressNotification();
+ return mUiBot.getVisibleObject(
+ mContext.getString(R.string.bugreport_screenshot_action).toUpperCase());
+ }
+
+ /**
+ * Takes a screenshot using the system notification.
+ */
+ private void takeScreenshot() throws Exception {
+ UiObject screenshotButton = getScreenshotButton();
+ mUiBot.click(screenshotButton, "screenshot_button");
+ }
+
+ private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
+ UiObject screenshotButton = getScreenshotButton();
+ int maxAttempts = SCREENSHOT_DELAY_SECONDS + 5;
+ int i = 0;
+ do {
+ boolean enabled = screenshotButton.isEnabled();
+ if (enabled == expectedEnabled) {
+ return screenshotButton;
+ }
+ i++;
+ Log.v(TAG, "Sleeping for 1 second while waiting for screenshot.enable to be "
+ + expectedEnabled + " (attempt " + i + ")");
+ Thread.sleep(DateUtils.SECOND_IN_MILLIS);
+ } while (i <= maxAttempts);
+ fail("screenshot.enable didn't change to " + expectedEnabled + " in " + maxAttempts + "s");
+ return screenshotButton;
+ }
+
+ private void assertScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
+ UiObject screenshotButton = getScreenshotButton();
+ assertEquals("wrong state for screenshot button ", expectedEnabled,
+ screenshotButton.isEnabled());
+ }
+
+ /**
+ * Helper class containing the UiObjects present in the bugreport info dialog.
+ */
+ private final class DetailsUi {
+
+ final UiObject detailsButton;
+ final UiObject nameField;
+ final UiObject titleField;
+ final UiObject descField;
+ final UiObject okButton;
+ final UiObject cancelButton;
+
+ /**
+ * Gets the UI objects by opening the progress notification and clicking DETAILS.
+ */
+ DetailsUi(UiBot uiBot) {
+ openProgressNotification();
+ detailsButton = mUiBot.getVisibleObject(
+ mContext.getString(R.string.bugreport_info_action).toUpperCase());
+ mUiBot.click(detailsButton, "details_button");
+ // TODO: unhardcode resource ids
+ nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name");
+ titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title");
+ descField = mUiBot.getVisibleObjectById("com.android.shell:id/description");
+ okButton = mUiBot.getObjectById("android:id/button1");
+ cancelButton = mUiBot.getObjectById("android:id/button2");
+ }
+
+ /**
+ * Takes focus away from the name field so it can be validated.
+ */
+ void focusAwayFromName() {
+ mUiBot.click(titleField, "title_field"); // Change focus.
+ mUiBot.pressBack(); // Dismiss keyboard.
+ }
+
+ void reOpen() {
+ openProgressNotification();
+ mUiBot.click(detailsButton, "details_button");
+
+ }
+
+ void clickOk() {
+ mUiBot.click(okButton, "details_ok_button");
+ }
+
+ void clickCancel() {
+ mUiBot.click(cancelButton, "details_cancel_button");
+ }
+ }
}
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index c871727..384c3da 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -79,6 +79,17 @@
}
/**
+ * Gets an object that might not yet be available in current UI.
+ *
+ * @param id Object's fully-qualified resource id (like {@code android:id/button1})
+ */
+ public UiObject getObjectById(String id) {
+ boolean gotIt = mDevice.wait(Until.hasObject(By.res(id)), mTimeout);
+ assertTrue("object with id '(" + id + "') not visible yet", gotIt);
+ return getVisibleObjectById(id);
+ }
+
+ /**
* Gets an object which is guaranteed to be present in the current UI.
*
* @param text Object's text as displayed by the UI.
@@ -90,6 +101,18 @@
}
/**
+ * Gets an object which is guaranteed to be present in the current UI.
+ *
+ * @param text Object's text as displayed by the UI.
+ */
+ public UiObject getVisibleObjectById(String id) {
+ UiObject uiObject = mDevice.findObject(new UiSelector().resourceId(id));
+ assertTrue("could not find object with id '" + id+ "'", uiObject.exists());
+ return uiObject;
+ }
+
+
+ /**
* Clicks on a UI element.
*
* @param uiObject UI element to be clicked.
@@ -151,4 +174,8 @@
click(activity, name);
}
}
+
+ public void pressBack() {
+ mDevice.pressBack();
+ }
}
diff --git a/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
new file mode 100644
index 0000000..51b7ba8
--- /dev/null
+++ b/packages/Shell/tests/src/com/android/shell/UtilitiesTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.shell;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+import static com.android.shell.BugreportProgressService.isValid;
+
+@SmallTest
+public class UtilitiesTest extends TestCase {
+
+ public void testIsValidChar_valid() {
+ String validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ for (int i = 0; i < validChars.length(); i++) {
+ char c = validChars.charAt(i);
+ assertTrue("char '" + c + "' should be valid", isValid(c));
+ }
+ }
+
+ public void testIsValidChar_invalid() {
+ String validChars = "/.<>;:'\'\"\\+=*&^%$#@!`~áéíóúãñÂÊÎÔÛ";
+ for (int i = 0; i < validChars.length(); i++) {
+ char c = validChars.charAt(i);
+ assertFalse("char '" + c + "' should not be valid", isValid(c));
+ }
+ }
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index eb63e5d..61cad2f 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -8,7 +8,11 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
Keyguard \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-v7-appcompat \
+ android-support-v14-preference
+
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_PACKAGE_NAME := SystemUI
@@ -22,10 +26,13 @@
LOCAL_RESOURCE_DIR := \
frameworks/base/packages/Keyguard/res \
$(LOCAL_PATH)/res \
+ frameworks/support/v7/preference/res \
+ frameworks/support/v14/preference/res \
+ frameworks/support/v7/appcompat/res \
frameworks/support/v7/recyclerview/res
LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages com.android.keyguard:android.support.v7.recyclerview
+ --extra-packages com.android.keyguard:android.support.v7.recyclerview:android.support.v7.preference:android.support.v14.preference:android.support.v7.appcompat
ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 51b84f5..9546c8d 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -139,6 +139,9 @@
<!-- Adding Quick Settings tiles -->
<uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
+ <!-- Block notifications inline notifications -->
+ <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
@@ -186,7 +189,7 @@
<activity android:name=".tuner.TunerActivity"
android:enabled="false"
android:icon="@drawable/tuner"
- android:theme="@android:style/Theme.Material.Settings"
+ android:theme="@style/TunerSettings"
android:label="@string/system_ui_tuner"
android:process=":tuner"
android:exported="true">
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 75e7959..bc18221 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -10,6 +10,7 @@
public void setGlowScale(float);
}
+-keep class com.android.systemui.statusbar.car.CarStatusBar
-keep class com.android.systemui.statusbar.phone.PhoneStatusBar
-keep class com.android.systemui.statusbar.tv.TvStatusBar
@@ -27,3 +28,9 @@
public float getTaskProgress();
public void setTaskProgress(float);
}
+
+-keepclasseswithmembers class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keep class ** extends android.support.v14.preference.PreferenceFragment
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
new file mode 100644
index 0000000..f3be2ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/docked_divider_handle.xml b/packages/SystemUI/res/drawable/docked_divider_handle.xml
deleted file mode 100644
index 84c0343..0000000
--- a/packages/SystemUI/res/drawable/docked_divider_handle.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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">
- <size android:height="@dimen/docked_divider_handle_height"
- android:width="@dimen/docked_divider_handle_width" />
- <corners android:radius="1dp" />
- <solid android:color="@color/docked_divider_handle" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/SystemUI/res/drawable/ic_colorize.xml
similarity index 61%
copy from packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
copy to packages/SystemUI/res/drawable/ic_colorize.xml
index f11b690..79fd6d9 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
+++ b/packages/SystemUI/res/drawable/ic_colorize.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2015 The Android Open Source Project
+ Copyright (C) 2015 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF0000FF"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M20.71,5.63l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-3.12,3.12 -1.93,-1.91 -1.41,1.41 1.42,1.42L3.0,16.25L3.0,21.0l4.75,0.0l8.92,-8.92 1.42,1.42 1.41,-1.41 -1.92,-1.92 3.12,-3.12c0.4,0.0 0.4,-1.0 0.01,-1.42zM6.92,19.0L5.0,17.08l8.06,-8.06 1.92,1.92L6.92,19.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
index ba09ebe..951269b 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_dark.xml
@@ -19,6 +19,6 @@
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="@color/recents_task_bar_dark_dismiss_color"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_dismiss_light.xml b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
index be0825c..1f44c1c 100644
--- a/packages/SystemUI/res/drawable/recents_dismiss_light.xml
+++ b/packages/SystemUI/res/drawable/recents_dismiss_light.xml
@@ -19,6 +19,6 @@
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
- android:fillColor="@color/recents_task_bar_light_dismiss_color"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M38.000000,12.800000l-2.799999,-2.800000 -11.200001,11.200001 -11.200000,-11.200001 -2.800000,2.800000 11.200001,11.200000 -11.200001,11.200001 2.800000,2.799999 11.200000,-11.200001 11.200001,11.200001 2.799999,-2.799999 -11.200001,-11.200001z"/>
</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml b/packages/SystemUI/res/drawable/recents_move_task_freeform_dark.xml
similarity index 93%
rename from packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
rename to packages/SystemUI/res/drawable/recents_move_task_freeform_dark.xml
index feb612c..ce07b2d 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
+++ b/packages/SystemUI/res/drawable/recents_move_task_freeform_dark.xml
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,4.0l10.0,0.0l0.0,10.0L4.0,14.0L4.0,4.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml b/packages/SystemUI/res/drawable/recents_move_task_freeform_light.xml
similarity index 92%
copy from packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
copy to packages/SystemUI/res/drawable/recents_move_task_freeform_light.xml
index feb612c..bf452ae 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_top_left.xml
+++ b/packages/SystemUI/res/drawable/recents_move_task_freeform_light.xml
@@ -19,6 +19,6 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,4.0l10.0,0.0l0.0,10.0L4.0,14.0L4.0,4.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml b/packages/SystemUI/res/drawable/recents_move_task_fullscreen_dark.xml
similarity index 81%
copy from packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
copy to packages/SystemUI/res/drawable/recents_move_task_fullscreen_dark.xml
index aee0b7f..4160efb 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/recents_move_task_fullscreen_dark.xml
@@ -19,15 +19,15 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M0.0,8.0l4.0,0.0 0.0,-4.0 4.0,0.0 0.0,-4.0 -8.0,0.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M4.0,16.0l-4.0,0.0 0.0,8.0 8.0,0.0 0.0,-4.0 -4.0,0.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M16.0,0.0l0.0,4.0 4.0,0.0 0.0,4.0 4.0,0.0 0.0,-8.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_dark_icon_color"
android:pathData="M20.0,20.0l-4.0,0.0 0.0,4.0 8.0,0.0 0.0,-8.0 -4.0,0.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml b/packages/SystemUI/res/drawable/recents_move_task_fullscreen_light.xml
similarity index 81%
rename from packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
rename to packages/SystemUI/res/drawable/recents_move_task_fullscreen_light.xml
index aee0b7f..f424bf6 100644
--- a/packages/SystemUI/res/drawable/vector_drawable_place_fullscreen.xml
+++ b/packages/SystemUI/res/drawable/recents_move_task_fullscreen_light.xml
@@ -19,15 +19,15 @@
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M0.0,8.0l4.0,0.0 0.0,-4.0 4.0,0.0 0.0,-4.0 -8.0,0.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M4.0,16.0l-4.0,0.0 0.0,8.0 8.0,0.0 0.0,-4.0 -4.0,0.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M16.0,0.0l0.0,4.0 4.0,0.0 0.0,4.0 4.0,0.0 0.0,-8.0z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@color/recents_task_bar_light_icon_color"
android:pathData="M20.0,20.0l-4.0,0.0 0.0,4.0 8.0,0.0 0.0,-8.0 -4.0,0.0z"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml
deleted file mode 100644
index 14f1981..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_bottom.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
deleted file mode 100644
index cea6324..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_left.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM4.0,10.0l10.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
deleted file mode 100644
index c2ae9c8..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_bottom_right.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,20.0L10.0,20.0L10.0,10.0l10.0,0.0L20.0,20.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
deleted file mode 100644
index 79ade42..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF0000FF"
- android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
deleted file mode 100644
index 49c2a38..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF0000FF"
- android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
deleted file mode 100644
index c3abec2..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF0000FF"
- android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_left.xml
deleted file mode 100644
index 078f83c..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_left.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_right.xml
deleted file mode 100644
index 86730db..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_right.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
deleted file mode 100644
index 9f4ee49..0000000
--- a/packages/SystemUI/res/drawable/vector_drawable_place_top_right.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM20.0,14.0L10.0,14.0L10.0,4.0l10.0,0.0L20.0,14.0z"/>
-</vector>
diff --git a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
deleted file mode 100644
index 0a4c086..0000000
--- a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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:padding="16dp"
- android:orientation="vertical"
- android:descendantFocusability="beforeDescendants"
- android:focusableInTouchMode="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/place_dock_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_left" />
- <Button
- android:id="@+id/place_dock_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_right" />
- <Button
- android:id="@+id/place_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_left" />
- <Button
- android:id="@+id/place_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_right" />
- <Button
- android:id="@+id/place_full"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_fullscreen" />
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
deleted file mode 100644
index bf5207a..0000000
--- a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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:padding="16dp"
- android:orientation="vertical"
- android:descendantFocusability="beforeDescendants"
- android:focusableInTouchMode="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/place_dock_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_top" />
- <Button
- android:id="@+id/place_dock_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_bottom" />
- <Button
- android:id="@+id/place_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top" />
- <Button
- android:id="@+id/place_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom" />
- <Button
- android:id="@+id/place_full"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_fullscreen" />
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
deleted file mode 100644
index 6e92afc..0000000
--- a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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:padding="16dp"
- android:orientation="vertical"
- android:descendantFocusability="beforeDescendants"
- android:focusableInTouchMode="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/place_dock_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_left" />
- <Button
- android:id="@+id/place_dock_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_right" />
- <Button
- android:id="@+id/place_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_left" />
- <Button
- android:id="@+id/place_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_right" />
- <Button
- android:id="@+id/place_top_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top_left" />
- <Button
- android:id="@+id/place_top_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top_right" />
- <Button
- android:id="@+id/place_bottom_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom_left" />
- <Button
- android:id="@+id/place_bottom_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom_right" />
- <Button
- android:id="@+id/place_full"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_fullscreen" />
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
deleted file mode 100644
index faa5f4b..0000000
--- a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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:padding="16dp"
- android:orientation="vertical"
- android:descendantFocusability="beforeDescendants"
- android:focusableInTouchMode="true">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <Button
- android:id="@+id/place_dock_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_top" />
- <Button
- android:id="@+id/place_dock_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_dock_bottom" />
- <Button
- android:id="@+id/place_top"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top" />
- <Button
- android:id="@+id/place_bottom"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom" />
- <Button
- android:id="@+id/place_top_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top_left" />
- <Button
- android:id="@+id/place_top_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_top_right" />
- <Button
- android:id="@+id/place_bottom_left"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom_left" />
- <Button
- android:id="@+id/place_bottom_right"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_bottom_right" />
- <Button
- android:id="@+id/place_full"
- android:layout_width="36dp"
- android:layout_height="36dp"
- android:layout_weight="1"
- android:layout_margin="10dp"
- android:background="@drawable/vector_drawable_place_fullscreen" />
- </LinearLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/assist_orb.xml b/packages/SystemUI/res/layout/assist_orb.xml
index ab0a0a5..0036ed6 100644
--- a/packages/SystemUI/res/layout/assist_orb.xml
+++ b/packages/SystemUI/res/layout/assist_orb.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2012, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml
new file mode 100644
index 0000000..f7f673d
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_navigation_bar.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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.statusbar.car.CarNavigationBarView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="@drawable/system_bar_background">
+
+ <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
+ rotation so skip this level of the heirarchy.
+ -->
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:id="@+id/nav_buttons"
+ android:animateLayoutChanges="true">
+
+ <!-- Buttons get populated here from a car_arrays.xml. -->
+ </LinearLayout>
+
+ <!-- lights out layout to match exactly -->
+ <LinearLayout
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:id="@+id/lights_out"
+ android:visibility="gone">
+ <!-- Must match nav_buttons. -->
+ </LinearLayout>
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 22ed216..7ea5027 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -24,10 +24,9 @@
android:id="@+id/docked_divider_background"
android:background="@color/docked_divider_background"/>
- <ImageButton
+ <com.android.systemui.stackdivider.DividerHandleView
style="@style/DockedDividerHandle"
android:id="@+id/docked_divider_handle"
- android:background="@null"
- android:src="@drawable/docked_divider_handle"/>
+ android:background="@null"/>
</com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
new file mode 100644
index 0000000..460433e
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2015 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/keyboard_shortcuts_wrapper"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="40dp"
+ android:focusable="true">
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 6ae5cf3..a20ec8e 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index d58664f..8498a4f 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index c9dbc79..071b7c8 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -24,42 +24,27 @@
android:clickable="true"
android:gravity="top|start"
android:orientation="vertical"
- android:paddingEnd="8dp"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:background="@color/notification_guts_text_color" >
<!-- header -->
- <FrameLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
+ android:paddingBottom="8dp"
android:paddingTop="8dp"
- android:paddingBottom="16dp" >
+ android:id="@+id/notification_guts_header"
+ android:orientation="horizontal"
+ android:layout_gravity="center_vertical|start">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/notification_guts_header"
- android:orientation="vertical"
- android:layout_gravity="center_vertical|start"
- android:layout_marginEnd="52dp">
-
- <LinearLayout
- android:id="@+id/notification_guts_app_details"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:clipChildren="false"
- android:layout_gravity="start|top"
- android:gravity="center_vertical"
- >
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="18dp"
- android:layout_height="18dp"
- android:layout_marginEnd="3dp"
- android:src="@android:drawable/arrow_down_float" />
- <TextView
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="18dp"
+ android:layout_height="18dp"
+ android:layout_marginEnd="3dp"
+ android:src="@android:drawable/arrow_down_float" />
+ <TextView
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -67,7 +52,7 @@
android:layout_marginStart="3dp"
android:layout_marginEnd="4dp"
android:textColor="@color/notification_guts_title_color" />
- <TextView
+ <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/debug_info"
@@ -76,34 +61,12 @@
android:layout_gravity="bottom|start"
android:visibility="gone"
android:textColor="#ffffff" />
- </LinearLayout>
-
- <TextView
- android:id="@+id/topic_details"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
- android:textColor="@color/notification_guts_text_color"
- android:layout_alignParentBottom="true"
- android:layout_alignParentStart="true" />
- </LinearLayout>
-
- <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
- android:id="@+id/notification_inspect_item"
- android:layout_width="52dp"
- android:layout_height="match_parent"
- android:layout_weight="0"
- android:gravity="center"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/status_bar_notification_inspect_item_title"
- android:src="@drawable/ic_settings" />
- </FrameLayout>
+ </LinearLayout>
<!-- Importance slider -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
android:orientation="vertical"
android:clickable="false"
android:focusable="false"
@@ -116,8 +79,7 @@
android:textAppearance="@android:style/TextAppearance.Material.Subhead"
android:textColor="@color/notification_guts_text_color"
android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:text="@*android:string/notification_importance_title"/>
+ android:fadingEdge="horizontal"/>
<TextView
android:id="@+id/summary"
@@ -133,7 +95,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="6dp" >
+ android:paddingTop="8dp" >
<ImageView
android:id="@+id/low_importance"
@@ -162,5 +124,53 @@
android:layout_height="24dp"/>
</FrameLayout>
+
+ <RadioGroup
+ android:id="@+id/apply_to"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dp">
+ <RadioButton android:id="@+id/apply_to_topic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@color/notification_guts_text_color"
+ android:visibility="gone"/>
+ <RadioButton android:id="@+id/apply_to_app"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/apply_to_app"
+ android:textColor="@color/notification_guts_text_color"
+ android:visibility="gone"/>
+ </RadioGroup>
+ </LinearLayout>
+ <!-- buttons -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:paddingTop="8dp"
+ android:paddingBottom="16dp" >
+
+ <TextView
+ android:id="@+id/more_settings"
+ android:text="@string/notification_more_settings"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:paddingEnd="24dp"
+ android:paddingStart="12dp"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/done"
+ android:text="@string/notification_done"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.NotificationGuts"
+ android:background="@drawable/btn_borderless_rect"
+ android:gravity="center"
+ android:focusable="true"/>
</LinearLayout>
</com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/preference_matrix.xml b/packages/SystemUI/res/layout/preference_matrix.xml
new file mode 100644
index 0000000..ebf486f
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_matrix.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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:orientation="horizontal">
+ <Space
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1" />
+ <GridLayout
+ android:id="@+id/edit_group"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:rowCount="5"
+ android:columnCount="5">
+
+ <Space android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_r"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_g"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_b"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Space android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_r"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_g"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <TextView
+ android:layout_width="40dp"
+ android:text="@string/color_modification_b"
+ android:gravity="center"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ <Space android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+ <EditText android:inputType="numberDecimal" android:layout_width="40dp" />
+
+ </GridLayout>
+ <Button
+ android:id="@+id/apply"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="bottom"
+ android:text="@string/color_apply" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_settings.xml b/packages/SystemUI/res/layout/preference_widget_settings.xml
new file mode 100644
index 0000000..082a295
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_settings.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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_height="wrap_content"
+ android:layout_width="wrap_content">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="4dp"
+ android:clickable="false"
+ android:focusable="false" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <ImageView
+ android:id="@+id/widget_icon"
+ android:layout_width="50dp"
+ android:layout_height="24dp"
+ android:tint="@android:color/black"
+ android:src="@drawable/ic_settings"
+ android:layout_gravity="center_vertical" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/preference_widget_switch.xml b/packages/SystemUI/res/layout/preference_widget_switch.xml
new file mode 100644
index 0000000..49610de
--- /dev/null
+++ b/packages/SystemUI/res/layout/preference_widget_switch.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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_height="wrap_content"
+ android:layout_width="wrap_content">
+
+ <RadioButton
+ android:id="@+id/radio_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:focusable="false"
+ android:layout_marginEnd="4dp" />
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:attr/listDivider" />
+
+ <Switch
+ android:id="@*android:id/switch_widget"
+ android:layout_width="50dp"
+ android:layout_height="wrap_content"
+ android:focusable="false"
+ android:clickable="false"
+ android:background="@null" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index a995ec7..2377684 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -96,14 +96,14 @@
<LinearLayout
android:id="@+id/date_time_group"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="28dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:orientation="horizontal">
<include layout="@layout/split_clock_view"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginTop="2dp"
android:id="@+id/clock" />
@@ -111,28 +111,28 @@
<com.android.systemui.statusbar.policy.DateView
android:id="@+id/date"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:layout_marginStart="6dp"
android:layout_marginTop="8dp"
- android:layout_alignParentTop="true"
android:drawableStart="@drawable/header_dot"
android:drawablePadding="6dp"
android:singleLine="true"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
android:textSize="@dimen/qs_time_collapsed_size"
+ android:gravity="top"
systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm" />
<com.android.systemui.statusbar.AlphaOptimizedButton
android:id="@+id/alarm_status"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
+ android:layout_height="match_parent"
+ android:layout_marginTop="8dp"
android:drawablePadding="6dp"
android:drawableStart="@drawable/ic_access_alarms_small"
android:textColor="#64ffffff"
android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
- android:minHeight="36dp"
android:paddingStart="6dp"
+ android:gravity="top"
android:background="?android:attr/selectableItemBackground"
android:visibility="gone" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 2c010dd..16ff14c 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -33,12 +33,6 @@
android:layout_height="match_parent">
</com.android.systemui.recents.views.RecentsView>
- <!-- Empty View -->
- <ViewStub android:id="@+id/empty_view_stub"
- android:layout="@layout/recents_empty"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<!-- History View -->
<ViewStub android:id="@+id/history_view_stub"
android:layout="@layout/recents_history"
diff --git a/packages/SystemUI/res/layout/recents_history_button.xml b/packages/SystemUI/res/layout/recents_history_button.xml
index 601c5ed..8c96fc6 100644
--- a/packages/SystemUI/res/layout/recents_history_button.xml
+++ b/packages/SystemUI/res/layout/recents_history_button.xml
@@ -26,5 +26,4 @@
android:shadowDx="0"
android:shadowDy="2"
android:shadowRadius="5"
- android:fontFamily="sans-serif-medium"
- android:visibility="invisible" />
\ No newline at end of file
+ android:fontFamily="sans-serif-medium" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_history_task.xml b/packages/SystemUI/res/layout/recents_history_task.xml
index b9de156..ae11006 100644
--- a/packages/SystemUI/res/layout/recents_history_task.xml
+++ b/packages/SystemUI/res/layout/recents_history_task.xml
@@ -13,15 +13,30 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<TextView
+<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:theme="@android:style/Theme.Material"
android:layout_width="match_parent"
android:layout_height="48dp"
- android:paddingLeft="32dp"
- android:gravity="start|center_vertical"
- android:textSize="14sp"
- android:textColor="#FFFFFF"
- android:fontFamily="sans-serif-medium"
- android:background="?android:selectableItemBackground"
- android:alpha="1" />
\ No newline at end of file
+ android:orientation="horizontal"
+ android:clickable="true"
+ android:focusable="true"
+ android:background="?android:selectableItemBackground">
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center"
+ android:layout_marginStart="16dp" />
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_gravity="end"
+ android:paddingStart="16dp"
+ android:gravity="start|center_vertical"
+ android:textSize="14sp"
+ android:textColor="#FFFFFF"
+ android:fontFamily="sans-serif-medium" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 2b82b05..5b44c17 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -34,9 +34,10 @@
android:layout_gravity="bottom|right"
android:layout_marginRight="15dp"
android:layout_marginBottom="15dp"
- android:translationZ="2dp"
+ android:translationZ="4dp"
android:contentDescription="@string/recents_lock_to_app_button_label"
- android:background="@drawable/recents_lock_to_task_button_bg">
+ android:background="@drawable/recents_lock_to_task_button_bg"
+ android:visibility="invisible">
<ImageView
android:layout_width="@dimen/recents_lock_to_app_icon_size"
android:layout_height="@dimen/recents_lock_to_app_icon_size"
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml
index 2168e8b..04f18c5 100644
--- a/packages/SystemUI/res/layout/recents_task_view_header.xml
+++ b/packages/SystemUI/res/layout/recents_task_view_header.xml
@@ -20,7 +20,7 @@
android:layout_height="@dimen/recents_task_bar_height"
android:layout_gravity="top|center_horizontal">
<com.android.systemui.recents.views.FixedSizeImageView
- android:id="@+id/application_icon"
+ android:id="@+id/icon"
android:contentDescription="@string/recents_app_info_button_label"
android:layout_width="@dimen/recents_task_view_application_icon_size"
android:layout_height="@dimen/recents_task_view_application_icon_size"
@@ -29,12 +29,12 @@
android:padding="8dp"
android:background="@drawable/recents_button_bg" />
<TextView
- android:id="@+id/activity_description"
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="64dp"
- android:layout_marginEnd="64dp"
+ android:layout_marginEnd="112dp"
android:textSize="16sp"
android:textColor="#ffffffff"
android:text="@string/recents_empty_message"
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index f8bd6fd..198e658 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index a5b3a83..aaa5a09 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index bfa13e2..12cf137 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
index 1675773..adfaed13 100644
--- a/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_recent_apps.xml
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
**
** Copyright 2011, The Android Open Source Project
**
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 0cea7ae..62fdd42 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -65,7 +65,7 @@
android:id="@+id/notification_guts_stub"
android:inflatedId="@+id/notification_guts"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
/>
</com.android.systemui.statusbar.ExpandableNotificationRow>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a08c9ca..0187993 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"soek"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kon nie <xliff:g id="APP">%s</xliff:g> begin nie."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Meer"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Geskiedenis"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> meer"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Verdeel horisontaal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verdeel vertikaal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Verdeel gepasmaak"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batteryspaarder is aan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Verminder werkverrigting en agtergronddata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Skakel batterybespaarder af"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud versteek"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sal alles begin vasvang wat op jou skerm gewys word."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Moenie weer wys nie"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Vee alles uit"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Pas toe op <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-kennisgewings"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Pas toe op alle kennisgewings van hierdie program af"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Min belang"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normale belang"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Dringende belang"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Moet nooit hierdie kennisgewings wys nie"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Wys onderaan die kennisgewinglys sonder \'n geluid"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Wys hierdie kennisgewings sonder geluide"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Wys boaan die kennisgewinglys en maak \'n geluid"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Verskyn vlugtig op die skerm en maak \'n geluid"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleure"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Aandkleure"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Gepasmaakte kleure"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleure"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Kleurverandering"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Wys kitsinstellings-teël"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Aktiveer gepasmaakte omskepping"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Pas toe"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Bevestig instellings"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Sommige kleurinstellings kan hierdie toestel onbruikbaar maak. Klik OK om hierdie kleurinstellings te bevestig; andersins sal hierdie instellings ná 10 sekondes teruggestel word."</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 4591f24..503a767 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ፈልግ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ን መጀመር አልተቻለም።"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"ተጨማሪ"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ታሪክ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ተጨማሪ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"አግድም ክፈል"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ቁልቁል ክፈል"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"በብጁ ክፈል"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"የባትሪ ኃይል ቆጣቢ በርቷል"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"አፈጻጸምን እና የጀርባ ውሂብ ይቀንሳል"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ባትሪ ቆጣቢን አጥፋ"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"ይዘቶች ተደብቀዋል"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> በማያ ገጽዎ ላይ የታየውን ነገር በሙሉ ማንሳት ይጀምራል።"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ዳግመኛ አታሳይ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ሁሉንም አጽዳ"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"በ<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ማሳወቂያዎች ላይ ተግብር"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ከዚህ መተግበሪያ በሚመጡ ሁሉም ማሳወቂያዎች ላይ ተግብር"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"የታገዱ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"ዝቅተኛ አስፈላጊነት"</string>
+ <string name="default_importance" msgid="8192107689995742653">"መደበኛ አስፈላጊነት"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ከፍተኛ አስፈላጊነት"</string>
+ <string name="max_importance" msgid="5089005872719563894">"አስቸኳይ አስፈላጊነት"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"እነዚህን ማሳወቂያዎች በጭራሽ አታሳይ"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"በማሳወቂያዎች ዝርዝር ላይኛው ክፍል ላይ አሳይና ድምፅ አሰማ"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ወደ ገጸ ማያው ይመልከቱና ድምፅ ይቅረጹ"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"መደበኛ ቀለሞች"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"የለሊት ቀለሞች"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ብጁ ቀለሞች"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"የማይታወቁ ቀለሞች"</string>
+ <string name="color_transform" msgid="6985460408079086090">"የቀለም ማሻሻያ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"የፈጣን ቅንብሮች ሰቅን አሳይ"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"ብጁ ቅየራን አንቃ"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ተግብር"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ቅንብሮችን ያረጋግጡ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"አንዳንድ የቀለም ቅንብሮች ይህን መሣሪያ የማይጠቅም ሊያደርጉት ይችላሉ። እነዚህን የቀለም ቅንብሮች ለማረጋገጥ እሺ የሚለውን ጠቅ ያድርጉ፣ አለበለዚያ እነዚህ ቅንብሮች ከ10 ሰከንዶች በኋላ ዳግም ይጀምራሉ።"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index beeb923..d89d036 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -305,7 +305,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"بحث"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"تعذر بدء <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"المزيد"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"السجلّ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> أخرى"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسيم أفقي"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسيم رأسي"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"تقسيم مخصص"</string>
@@ -368,7 +368,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"لخفض مستوى الأداء وبيانات الخلفية"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"إيقاف توفير شحن البطارية"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"محو الكل"</string>
@@ -453,4 +452,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"تشغيل"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"التطبيق على إشعارات <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"التطبيق في جميع الإشعارات من هذا التطبيق"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"تم الحظر"</string>
+ <string name="low_importance" msgid="4109929986107147930">"أهمية منخفضة"</string>
+ <string name="default_importance" msgid="8192107689995742653">"أهمية عادية"</string>
+ <string name="high_importance" msgid="1527066195614050263">"أهمية عالية"</string>
+ <string name="max_importance" msgid="5089005872719563894">"أهمية ملحَّة"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"عدم عرض هذه الإشعارات"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"العرض أسفل قائمة الإشعارات بدون تنبيه صوتي"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"العرض أعلى قائمة الإشعارات مع تنبيه صوتي"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"الظهور سريعًا على الشاشة مع تنبيه صوتي"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
+ <string name="notification_done" msgid="5279426047273930175">"تم"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ألوان عادية"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ألوان ليلية"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ألوان مخصصة"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"ألوان غير معروفة"</string>
+ <string name="color_transform" msgid="6985460408079086090">"إشعار الألوان"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"إظهار قسم الإعدادات السريعة"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"تمكين التحويل المخصص"</string>
+ <string name="color_apply" msgid="9212602012641034283">"تطبيق"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"تأكيد الإعدادات"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"يمكن أن تتسبب بعض إعدادات الألوان في تعطيل إمكانية استخدام الجهاز. يمكنك النقر على \"موافق\" لتأكيد إعدادات الألوان هذه، وإلا فستتم إعادة تعيين هذه الإعدادات بعد 10 ثوانٍ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index b2026a8..55f0841 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"axtarış"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlana bilmir."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Daha çox"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Tarixçə"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Daha çox"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Üfüqi Böl"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Şaquli Böl"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Fərdi Böl"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Enerji qənaəti aktivdir"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı azaldır və arxa fon datasını məhdudlaşdırır"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Enerjiyə qənaət rejimini deaktiv edin"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Məzmun gizlidir"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ekranınızda olan hər şeyin şəklini çəkəcək."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Daha göstərmə"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hamısını silin"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivləşdirin"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirişlərinə müraciət edin"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Bu tətbiqdən olan bütün bildirişlərə müraciət edin"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloklanmış"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Az əhəmiyyətli"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normal əhəmiyyətli"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Çox əhəmiyyətli"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Təcili əhəmiyyətli"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirişləri heç vaxt göstərməyin"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Bildirişlər siyahısının aşağısında səssiz göstərin"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildişləri səssiz göstərin"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Ekranda nəzər salın və səsli edin"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normal rənglər"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Gecə rəngləri"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Xüsusi rənglər"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Naməlum rəng"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Rəng modifikasiyası"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Cəld ayarlar örtüyünü göstərin"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Xüsusi dəyişikliyi aktiv edin"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Tətbiq edin"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Ayarları təsdiq edin"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Bəzi renk ayarları bu cihazı yararsız edə bilər. Bu rənk ayarlarını təsdiq etmək üçün OK basın, əks halda bu ayarlar 10 saniyə sonra sıfırlanacaq."</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn-land/strings.xml b/packages/SystemUI/res/values-b+sr+Latn-land/strings.xml
new file mode 100644
index 0000000..8ebbb0b
--- /dev/null
+++ b/packages/SystemUI/res/values-b+sr+Latn-land/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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">
+ <string name="toast_rotation_locked" msgid="7609673011431556092">"Ekran je sada zaključan u vertikalnom položaju."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..4056963
--- /dev/null
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,476 @@
+<?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">
+ <string name="app_label" msgid="7164937344850004466">"UI sistema"</string>
+ <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Obriši"</string>
+ <string name="status_bar_recent_remove_item_title" msgid="6026395868129852968">"Uklanjanje sa liste"</string>
+ <string name="status_bar_recent_inspect_item_title" msgid="7793624864528818569">"Informacije o aplikaciji"</string>
+ <string name="status_bar_no_recent_apps" msgid="7374907845131203189">"Nedavni ekrani se pojavljuju ovde"</string>
+ <string name="status_bar_accessibility_dismiss_recents" msgid="4576076075226540105">"Odbaci nedavne aplikacije"</string>
+ <plurals name="status_bar_accessibility_recent_apps" formatted="false" msgid="9138535907802238759">
+ <item quantity="one">%d ekran u Pregledu</item>
+ <item quantity="few">%d ekrana u Pregledu</item>
+ <item quantity="other">%d ekrana u Pregledu</item>
+ </plurals>
+ <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nema obaveštenja"</string>
+ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Tekuće"</string>
+ <string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obaveštenja"</string>
+ <string name="battery_low_title" msgid="6456385927409742437">"Nivo napunjenosti baterije je nizak"</string>
+ <string name="battery_low_percent_format" msgid="2900940511201380775">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
+ <string name="battery_low_percent_format_saver_started" msgid="6859235584035338833">"Još <xliff:g id="PERCENTAGE">%s</xliff:g>. Uključena je štednja baterije."</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Punjenje preko USB-a nije podržano.\nKoristite samo priloženi punjač."</string>
+ <string name="invalid_charger_title" msgid="3515740382572798460">"Punjenje preko USB-a nije podržano."</string>
+ <string name="invalid_charger_text" msgid="5474997287953892710">"Koristite samo punjač koji ste dobili."</string>
+ <string name="battery_low_why" msgid="4553600287639198111">"Podešavanja"</string>
+ <string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Želite li da uključite štednju baterije?"</string>
+ <string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Uključi"</string>
+ <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi štednju baterije"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Podešavanja"</string>
+ <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
+ <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatsko rotiranje ekrana"</string>
+ <string name="status_bar_settings_mute_label" msgid="554682549917429396">"UGASI"</string>
+ <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
+ <string name="status_bar_settings_notifications" msgid="397146176280905137">"Obaveštenja"</string>
+ <string name="bluetooth_tethered" msgid="7094101612161133267">"Veza preko Bluetooth-a"</string>
+ <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Podesi metode unosa"</string>
+ <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Fizička tastatura"</string>
+ <string name="usb_device_permission_prompt" msgid="834698001271562057">"Želite li da dozvolite aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa USB uređaju?"</string>
+ <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Želite li da dozvolite aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g> da pristupa USB pomoćnom uređaju?"</string>
+ <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Želite li da se otvori <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se priključi ovaj USB uređaj?"</string>
+ <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Želite li da se otvori <xliff:g id="ACTIVITY">%1$s</xliff:g> kada se priključi ovaj USB dodatak?"</string>
+ <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Instalirane aplikacije ne funkcionišu sa ovim USB pomoćnim uređajem. Saznajte više o njemu na adresi <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB pomoćni uređaj"</string>
+ <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
+ <string name="always_use_device" msgid="1450287437017315906">"Koristi podrazumevano za ovaj USB uređaj"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Koristi podrazumevano za ovaj USB dodatak"</string>
+ <string name="usb_debugging_title" msgid="4513918393387141949">"Želite li da dozvolite otklanjanje USB grešaka?"</string>
+ <string name="usb_debugging_message" msgid="2220143855912376496">"Digitalni otisak RSA ključa ovog računara je:\n<xliff:g id="FINGERPRINT">%1$s</xliff:g>"</string>
+ <string name="usb_debugging_always" msgid="303335496705863070">"Uvek dozvoli sa ovog računara"</string>
+ <string name="usb_debugging_secondary_user_title" msgid="6353808721761220421">"Otklanjanje grešaka na USB-u nije dozvoljeno"</string>
+ <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Korisnik koji je trenutno prijavljen na ovaj uređaj ne može da uključi otklanjanje grešaka na USB-u. Da biste koristili ovu funkciju, prebacite na korisnika sa administratorskim pravima."</string>
+ <string name="compat_mode_on" msgid="6623839244840638213">"Zumiraj na celom ekranu"</string>
+ <string name="compat_mode_off" msgid="4434467572461327898">"Razvuci na ceo ekran"</string>
+ <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Čuvanje snimka ekrana..."</string>
+ <string name="screenshot_saving_title" msgid="8242282144535555697">"Čuvanje snimka ekrana..."</string>
+ <string name="screenshot_saving_text" msgid="2419718443411738818">"Snimak ekrana se čuva."</string>
+ <string name="screenshot_saved_title" msgid="6461865960961414961">"Snimak ekrana je napravljen."</string>
+ <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite da biste videli snimak ekrana."</string>
+ <string name="screenshot_failed_title" msgid="705781116746922771">"Nije moguće napraviti snimak ekrana."</string>
+ <string name="screenshot_failed_text" msgid="1260203058661337274">"Nije moguće snimiti ekran zbog nedovoljne memorije ili to ne dozvoljava aplikacija ili organizacija."</string>
+ <string name="usb_preference_title" msgid="6551050377388882787">"Opcije USB prenosa datoteka"</string>
+ <string name="use_mtp_button_title" msgid="4333504413563023626">"Priključi kao medija plejer (MTP)"</string>
+ <string name="use_ptp_button_title" msgid="7517127540301625751">"Priključi kao kameru (PTP)"</string>
+ <string name="installer_cd_button_title" msgid="2312667578562201583">"Instaliraj Android prebacivanje datoteka za Mac"</string>
+ <string name="accessibility_back" msgid="567011538994429120">"Nazad"</string>
+ <string name="accessibility_home" msgid="8217216074895377641">"Početna"</string>
+ <string name="accessibility_menu" msgid="316839303324695949">"Meni"</string>
+ <string name="accessibility_recent" msgid="5208608566793607626">"Pregled"</string>
+ <string name="accessibility_search_light" msgid="1103867596330271848">"Pretražite"</string>
+ <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
+ <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
+ <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Glasovna pomoć"</string>
+ <string name="accessibility_unlock_button" msgid="128158454631118828">"Otključajte"</string>
+ <string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"Dugme za otključavanje, čeka se na otisak prsta"</string>
+ <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"Otključaj bez korišćenja otiska prsta"</string>
+ <string name="unlock_label" msgid="8779712358041029439">"otključaj"</string>
+ <string name="phone_label" msgid="2320074140205331708">"otvori telefon"</string>
+ <string name="voice_assist_label" msgid="3956854378310019854">"otvori glasovnu pomoć"</string>
+ <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
+ <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberi novi raspored zadataka"</string>
+ <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+ <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme Zum kompatibilnosti."</string>
+ <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje sa manjeg na veći ekran."</string>
+ <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je priključen."</string>
+ <string name="accessibility_bluetooth_disconnected" msgid="7416648669976870175">"Bluetooth je isključen."</string>
+ <string name="accessibility_no_battery" msgid="358343022352820946">"Nema baterije."</string>
+ <string name="accessibility_battery_one_bar" msgid="7774887721891057523">"Baterija od jedne crte."</string>
+ <string name="accessibility_battery_two_bars" msgid="8500650438735009973">"Baterija od dve crte."</string>
+ <string name="accessibility_battery_three_bars" msgid="2302983330865040446">"Baterija od tri crte."</string>
+ <string name="accessibility_battery_full" msgid="8909122401720158582">"Baterija je puna."</string>
+ <string name="accessibility_no_phone" msgid="4894708937052611281">"Nema telefona."</string>
+ <string name="accessibility_phone_one_bar" msgid="687699278132664115">"Signal telefona ima jednu crtu."</string>
+ <string name="accessibility_phone_two_bars" msgid="8384905382804815201">"Signal telefona od dve crte."</string>
+ <string name="accessibility_phone_three_bars" msgid="8521904843919971885">"Signal telefona od tri crte."</string>
+ <string name="accessibility_phone_signal_full" msgid="6471834868580757898">"Signal telefona je pun."</string>
+ <string name="accessibility_no_data" msgid="4791966295096867555">"Nema podataka."</string>
+ <string name="accessibility_data_one_bar" msgid="1415625833238273628">"Signal za podatke ima jednu crtu."</string>
+ <string name="accessibility_data_two_bars" msgid="6166018492360432091">"Signal za podatke od dve crte."</string>
+ <string name="accessibility_data_three_bars" msgid="9167670452395038520">"Signal za podatke od tri crte."</string>
+ <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Signal za podatke je najjači."</string>
+ <string name="accessibility_wifi_name" msgid="7202151365171148501">"Povezani ste sa <xliff:g id="WIFI">%s</xliff:g>."</string>
+ <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
+ <string name="accessibility_no_wimax" msgid="4329180129727630368">"Nema WiMAX signala."</string>
+ <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX signal ima jednu crtu."</string>
+ <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX signal ima dve crte."</string>
+ <string name="accessibility_wimax_three_bars" msgid="6116551636752103927">"WiMAX signal ima tri crte."</string>
+ <string name="accessibility_wimax_signal_full" msgid="2768089986795579558">"WiMAX signal je najjači."</string>
+ <string name="accessibility_ethernet_disconnected" msgid="5896059303377589469">"Veza sa eternetom je prekinuta."</string>
+ <string name="accessibility_ethernet_connected" msgid="2692130313069182636">"Eternet je povezan."</string>
+ <string name="accessibility_no_signal" msgid="7064645320782585167">"Nema signala."</string>
+ <string name="accessibility_not_connected" msgid="6395326276213402883">"Nije povezano."</string>
+ <string name="accessibility_zero_bars" msgid="3806060224467027887">"Nijedna crta."</string>
+ <string name="accessibility_one_bar" msgid="1685730113192081895">"Jedna crta."</string>
+ <string name="accessibility_two_bars" msgid="6437363648385206679">"Dve crte."</string>
+ <string name="accessibility_three_bars" msgid="2648241415119396648">"Tri crte."</string>
+ <string name="accessibility_signal_full" msgid="9122922886519676839">"Signal je najjači."</string>
+ <string name="accessibility_desc_on" msgid="2385254693624345265">"Uključeno."</string>
+ <string name="accessibility_desc_off" msgid="6475508157786853157">"Isključeno."</string>
+ <string name="accessibility_desc_connected" msgid="8366256693719499665">"Povezano je."</string>
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Povezivanje."</string>
+ <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
+ <string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
+ <string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
+ <string name="accessibility_data_connection_3g" msgid="8628562305003568260">"3G"</string>
+ <string name="accessibility_data_connection_3.5g" msgid="8664845609981692001">"3.5G"</string>
+ <string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
+ <string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
+ <string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
+ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Roming"</string>
+ <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
+ <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
+ <string name="accessibility_no_sim" msgid="8274017118472455155">"Nema SIM kartice."</string>
+ <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth privezivanje."</string>
+ <string name="accessibility_airplane_mode" msgid="834748999790763092">"Režim rada u avionu."</string>
+ <string name="accessibility_no_sims" msgid="3957997018324995781">"Nema SIM kartice."</string>
+ <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Promena mreže mobilnog operatera."</string>
+ <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija je na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
+ <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemska podešavanja."</string>
+ <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obaveštenja."</string>
+ <string name="accessibility_remove_notification" msgid="3603099514902182350">"Obriši obaveštenje."</string>
+ <string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS je omogućen."</string>
+ <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"Učitavanje GPS-a."</string>
+ <string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter je omogućen."</string>
+ <string name="accessibility_ringer_vibrate" msgid="666585363364155055">"Vibracija zvona."</string>
+ <string name="accessibility_ringer_silent" msgid="9061243307939135383">"Nečujno zvono."</string>
+ <!-- no translation found for accessibility_casting (6887382141726543668) -->
+ <skip />
+ <string name="accessibility_work_mode" msgid="2478631941714607225">"Režim rada"</string>
+ <string name="accessibility_recents_item_will_be_dismissed" msgid="395770242498031481">"Odbacite <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"Aplikacija <xliff:g id="APP">%s</xliff:g> je odbačena."</string>
+ <string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"Sve nedavno korišćene aplikacije su odbačene."</string>
+ <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"Pokrećemo <xliff:g id="APP">%s</xliff:g>."</string>
+ <string name="accessibility_recents_task_header" msgid="1437183540924535457">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="ACTIVITY_LABEL">%2$s</xliff:g>"</string>
+ <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obaveštenje je odbačeno."</string>
+ <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Prozor sa obaveštenjima."</string>
+ <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brza podešavanja."</string>
+ <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključani ekran."</string>
+ <string name="accessibility_desc_settings" msgid="3417884241751434521">"Podešavanja"</string>
+ <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
+ <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
+ <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Korisnik: <xliff:g id="USER">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi je isključen."</string>
+ <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wi-Fi je uključen."</string>
+ <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobilna mreža: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Baterija: <xliff:g id="STATE">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Režim rada u avionu je isključen."</string>
+ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Režim rada u avionu je uključen."</string>
+ <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Režim rada u avionu je isključen."</string>
+ <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Režim rada u avionu je uključen."</string>
+ <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Podešavanje Ne uznemiravaj je uključeno, samo prioritetni prekidi."</string>
+ <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Podešavanje Ne uznemiravaj je uključeno, potpuna tišina."</string>
+ <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Podešavanje Ne uznemiravaj je uključeno, samo alarmi."</string>
+ <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Podešavanje Ne uznemiravaj je isključeno."</string>
+ <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Podešavanje Ne uznemiravaj je isključeno."</string>
+ <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Podešavanje Ne uznemiravaj je uključeno."</string>
+ <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth je isključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth je uključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth se povezuje."</string>
+ <string name="accessibility_quick_settings_bluetooth_connected" msgid="4306637793614573659">"Bluetooth je povezan."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_off" msgid="2730003763480934529">"Bluetooth je isključen."</string>
+ <string name="accessibility_quick_settings_bluetooth_changed_on" msgid="8722351798763206577">"Bluetooth je uključen."</string>
+ <string name="accessibility_quick_settings_location_off" msgid="5119080556976115520">"Izveštavanje o lokaciji je isključeno."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="5809937096590102036">"Izveštavanje o lokaciji je uključeno."</string>
+ <string name="accessibility_quick_settings_location_changed_off" msgid="8526845571503387376">"Izveštavanje o lokaciji je isključeno."</string>
+ <string name="accessibility_quick_settings_location_changed_on" msgid="339403053079338468">"Izveštavanje o lokaciji je uključeno."</string>
+ <string name="accessibility_quick_settings_alarm" msgid="3959908972897295660">"Alarm je podešen za <xliff:g id="TIME">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_close" msgid="3115847794692516306">"Zatvorite tablu."</string>
+ <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
+ <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
+ <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Baterijska lampa je isključena."</string>
+ <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Baterijska lampa je uključena."</string>
+ <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Baterijska lampa je isključena."</string>
+ <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Baterijska lampa je uključena."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_off" msgid="4406577213290173911">"Inverzija boja je isključena."</string>
+ <string name="accessibility_quick_settings_color_inversion_changed_on" msgid="6897462320184911126">"Inverzija boja je uključena."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_off" msgid="5004708003447561394">"Mobilni hotspot je isključen."</string>
+ <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilni hotspot je uključen."</string>
+ <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Prebacivanje ekrana je zaustavljeno."</string>
+ <string name="accessibility_quick_settings_work_mode_off" msgid="7045417396436552890">"Režim rada je isključen."</string>
+ <string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Režim rada je uključen."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Režim rada je isključen."</string>
+ <string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Režim rada je uključen."</string>
+ <string name="accessibility_brightness" msgid="8003681285547803095">"Osvetljenost ekrana"</string>
+ <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G podaci su pauzirani"</string>
+ <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
+ <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
+ <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
+ <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zbog toga što ste dostigli podešeno ograničenje za podatke, uređaj je pauzirao korišćenje podataka tokom ostatka ovog ciklusa.\n\nAko nastavite, mobilni operater može da vam naplati dodatne troškove."</string>
+ <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
+ <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
+ <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
+ <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traži se GPS"</string>
+ <string name="gps_notification_found_text" msgid="4619274244146446464">"Lokaciju je podesio GPS"</string>
+ <string name="accessibility_location_active" msgid="2427290146138169014">"Ima aktivnih zahteva za lokaciju"</string>
+ <string name="accessibility_clear_all" msgid="5235938559247164925">"Obriši sva obaveštenja."</string>
+ <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Podešavanja obaveštenja"</string>
+ <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Podešavanja za <xliff:g id="APP_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
+ <string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran je zaključan u horizontalnom položaju."</string>
+ <string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran je zaključan u vertikalnom položaju."</string>
+ <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"Ekran će se sada automatski rotirati."</string>
+ <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ekran je sada zaključan u vertikalnom položaju."</string>
+ <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ekran je sada zaključan u horizontalnom položaju."</string>
+ <string name="dessert_case" msgid="1295161776223959221">"Vitrina sa poslasticama"</string>
+ <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
+ <string name="ethernet_label" msgid="7967563676324087464">"Eternet"</string>
+ <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne uznemiravaj"</string>
+ <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetni prekidi"</string>
+ <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Samo alarmi"</string>
+ <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Potpuna tišina"</string>
+ <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
+ <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> uređaja)"</string>
+ <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth isključen"</string>
+ <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nije dostupan nijedan upareni uređaj"</string>
+ <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Osvetljenost"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatska rotacija"</string>
+ <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotacija je zaključana"</string>
+ <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertikalni prikaz"</string>
+ <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontalni prikaz"</string>
+ <string name="quick_settings_ime_label" msgid="7073463064369468429">"Metod unosa"</string>
+ <string name="quick_settings_location_label" msgid="5011327048748762257">"Lokacija"</string>
+ <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Lokacija je isključena"</string>
+ <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Medijski uređaj"</string>
+ <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
+ <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Samo hitni pozivi"</string>
+ <string name="quick_settings_settings_label" msgid="5326556592578065401">"Podešavanja"</string>
+ <string name="quick_settings_time_label" msgid="4635969182239736408">"Vreme"</string>
+ <string name="quick_settings_user_label" msgid="5238995632130897840">"Ja"</string>
+ <string name="quick_settings_user_title" msgid="4467690427642392403">"Korisnik"</string>
+ <string name="quick_settings_user_new_user" msgid="9030521362023479778">"Novi korisnik"</string>
+ <string name="quick_settings_wifi_label" msgid="9135344704899546041">"Wi-Fi"</string>
+ <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Veza nije uspostavljena"</string>
+ <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
+ <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi je isključen"</string>
+ <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nije dostupna nijedna Wi-Fi mreža"</string>
+ <string name="quick_settings_cast_title" msgid="7709016546426454729">"Prebacivanje"</string>
+ <string name="quick_settings_casting" msgid="6601710681033353316">"Prebacivanje"</string>
+ <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Neimenovani uređaj"</string>
+ <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Spremno za prebacivanje"</string>
+ <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Nije dostupan nijedan uređaj"</string>
+ <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Osvetljenost"</string>
+ <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMATSKA"</string>
+ <string name="quick_settings_inversion_label" msgid="8790919884718619648">"Obrni boje"</string>
+ <string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekcije boje"</string>
+ <string name="quick_settings_more_settings" msgid="326112621462813682">"Još podešavanja"</string>
+ <string name="quick_settings_done" msgid="3402999958839153376">"Gotovo"</string>
+ <string name="quick_settings_connected" msgid="1722253542984847487">"Povezan"</string>
+ <string name="quick_settings_connecting" msgid="47623027419264404">"Povezuje se..."</string>
+ <string name="quick_settings_tethering_label" msgid="7153452060448575549">"Povezivanje"</string>
+ <string name="quick_settings_hotspot_label" msgid="6046917934974004879">"Hotspot"</string>
+ <string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obaveštenja"</string>
+ <string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Lampa"</string>
+ <string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Podaci za mobilne uređaje"</string>
+ <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Potrošnja podataka"</string>
+ <string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
+ <string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Preko ograničenja"</string>
+ <string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskoristili ste <xliff:g id="DATA_USED">%s</xliff:g>"</string>
+ <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ograničenje od <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
+ <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
+ <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Režim rada"</string>
+ <string name="recents_empty_message" msgid="8682129509540827999">"Nedavni ekrani se pojavljuju ovde"</string>
+ <string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
+ <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"kačenje ekrana"</string>
+ <string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
+ <string name="recents_launch_error_message" msgid="2969287838120550506">"Pokretanje aplikacije <xliff:g id="APP">%s</xliff:g> nije uspelo."</string>
+ <string name="recents_show_history_button_label" msgid="7062088196449747245">"Još"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Još <xliff:g id="NUMBER">%d</xliff:g>"</string>
+ <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
+ <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podeli vertikalno"</string>
+ <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođeno deljenje"</string>
+ <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Napunjena je"</string>
+ <string name="expanded_header_battery_charging" msgid="205623198487189724">"Punjenje"</string>
+ <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> dok se ne napuni"</string>
+ <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Ne puni se"</string>
+ <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se možda\nnadgleda"</string>
+ <string name="description_target_search" msgid="3091587249776033139">"Pretraga"</string>
+ <string name="description_direction_up" msgid="7169032478259485180">"Prevucite nagore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="description_direction_left" msgid="7207478719805562165">"Prevucite ulevo za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
+ <string name="zen_priority_introduction" msgid="3070506961866919502">"Neće vas uznemiravati zvukovi i vibracije, osim za alarme, podsetnike, događaje i pozivaoce koje izaberete."</string>
+ <string name="zen_priority_customize_button" msgid="7948043278226955063">"Prilagodi"</string>
+ <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Ovo blokira SVE zvukove i vibracije uključujući alarme, muziku, video snimke i igre. I dalje ćete moći da upućujete pozive."</string>
+ <string name="zen_silence_introduction" msgid="3137882381093271568">"Ovo blokira SVE zvukove i vibracije uključujući alarme, muziku, video snimke i igre."</string>
+ <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
+ <string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitna obaveštenja su u nastavku"</string>
+ <string name="notification_tap_again" msgid="8524949573675922138">"Dodirnite ponovo da biste otvorili"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite nagore da biste otključali"</string>
+ <string name="phone_hint" msgid="4872890986869209950">"Prevucite od ikone za telefon"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"Prevucite od ikone za glasovnu pomoć"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"Prevucite od ikone za kameru"</string>
+ <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Potpuna tišina. I čitači ekrana će biti isključeni."</string>
+ <string name="interruption_level_none" msgid="6000083681244492992">"Potpuna tišina"</string>
+ <string name="interruption_level_priority" msgid="6426766465363855505">"Samo prioritetni prekidi"</string>
+ <string name="interruption_level_alarms" msgid="5226306993448328896">"Samo alarmi"</string>
+ <string name="interruption_level_none_twoline" msgid="3957581548190765889">"Potpuna\ntišina"</string>
+ <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\npriorit. prekidi"</string>
+ <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
+ <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (pun je za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo se puni (napuniće se za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+ <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Zameni korisnika"</string>
+ <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Promenite korisnika, aktuelni korisnik je <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuelni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
+ <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"Prikaži profil"</string>
+ <string name="user_add_user" msgid="5110251524486079492">"Dodaj korisnika"</string>
+ <string name="user_new_user_name" msgid="426540612051178753">"Novi korisnik"</string>
+ <string name="guest_nickname" msgid="8059989128963789678">"Gost"</string>
+ <string name="guest_new_guest" msgid="600537543078847803">"Dodaj gosta"</string>
+ <string name="guest_exit_guest" msgid="7187359342030096885">"Ukloni gosta"</string>
+ <string name="guest_exit_guest_dialog_title" msgid="8480693520521766688">"Želite li da uklonite gosta?"</string>
+ <string name="guest_exit_guest_dialog_message" msgid="4155503224769676625">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string>
+ <string name="guest_exit_guest_dialog_remove" msgid="7402231963862520531">"Ukloni"</string>
+ <string name="guest_wipe_session_title" msgid="6419439912885956132">"Dobro došli nazad, goste!"</string>
+ <string name="guest_wipe_session_message" msgid="8476238178270112811">"Želite li da nastavite sesiju?"</string>
+ <string name="guest_wipe_session_wipe" msgid="5065558566939858884">"Počni iz početka"</string>
+ <string name="guest_wipe_session_dontwipe" msgid="1401113462524894716">"Da, nastavi"</string>
+ <string name="guest_notification_title" msgid="1585278533840603063">"Gost"</string>
+ <string name="guest_notification_text" msgid="335747957734796689">"Da biste izbrisali aplikacije i podatke, uklonite gosta"</string>
+ <string name="guest_notification_remove_action" msgid="8820670703892101990">"UKLONI GOSTA"</string>
+ <string name="user_logout_notification_title" msgid="1453960926437240727">"Odjavljivanje korisnika"</string>
+ <string name="user_logout_notification_text" msgid="3350262809611876284">"Odjavite aktuelnog korisnika"</string>
+ <string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
+ <string name="user_add_user_title" msgid="4553596395824132638">"Dodajete novog korisnika?"</string>
+ <string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba da podesi sopstveni prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
+ <string name="user_remove_user_title" msgid="4681256956076895559">"Želite li da uklonite korisnika?"</string>
+ <string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika će biti izbrisani."</string>
+ <string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
+ <string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
+ <string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje performanse i pozadinske podatke"</string>
+ <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi štednju baterije"</string>
+ <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> će početi da snima sve što se prikazuje na ekranu."</string>
+ <string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
+ <string name="clear_all_notifications_text" msgid="814192889771462828">"Obriši sve"</string>
+ <string name="media_projection_action_text" msgid="8470872969457985954">"Započni odmah"</string>
+ <string name="empty_shade_text" msgid="708135716272867002">"Nema obaveštenja"</string>
+ <string name="device_owned_footer" msgid="3802752663326030053">"Uređaj se možda nadgleda"</string>
+ <string name="profile_owned_footer" msgid="8021888108553696069">"Profil se možda nadgleda"</string>
+ <string name="vpn_footer" msgid="2388611096129106812">"Mreža se možda nadgleda"</string>
+ <string name="monitoring_title_device_owned" msgid="7121079311903859610">"Nadgledanje uređaja"</string>
+ <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"Nadgledanje profila"</string>
+ <string name="monitoring_title" msgid="169206259253048106">"Nadgledanje mreže"</string>
+ <string name="disable_vpn" msgid="4435534311510272506">"Onemogući VPN"</string>
+ <string name="disconnect_vpn" msgid="1324915059568548655">"Prekini vezu sa VPN-om"</string>
+ <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima. Više informacija potražite od administratora."</string>
+ <string name="monitoring_description_vpn" msgid="4445150119515393526">"Dali ste dozvolu aplikaciji da podešava VPN vezu.\n\nTa aplikacija može da nadgleda aktivnosti na uređaju i mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
+ <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nPovezani ste na VPN, koji može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i bezbedne veb-sajtove.\n\nViše informacija potražite od administratora."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora.\n\nPovezani ste i na VPN, koji može da nadgleda aktivnosti na ličnoj mreži."</string>
+ <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
+ <string name="monitoring_description_app" msgid="6259179342284742878">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
+ <string name="monitoring_description_app_personal" msgid="484599052118316268">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
+ <string name="monitoring_description_app_work" msgid="1754325860918060897">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
+ <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
+ <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Uređajem upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministrator može da nadgleda podešavanja, korporativni pristup, aplikacije, podatke povezane sa uređajem i informacije o lokaciji uređaja, kao i da upravlja njima.\n\nPovezani ste sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
+ <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
+ <string name="hidden_notifications_title" msgid="7139628534207443290">"Brže dobijajte obaveštenja"</string>
+ <string name="hidden_notifications_text" msgid="2326409389088668981">"Pregledajte ih pre otključavanja"</string>
+ <string name="hidden_notifications_cancel" msgid="3690709735122344913">"Ne, hvala"</string>
+ <string name="hidden_notifications_setup" msgid="41079514801976810">"Podesi"</string>
+ <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
+ <string name="volume_zen_end_now" msgid="3179845345429841822">"Prekini odmah"</string>
+ <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
+ <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
+ <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je zakačen"</string>
+ <string name="screen_pinning_description" msgid="3577937698406151604">"Zbog toga se on stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad da biste ga otkačili."</string>
+ <string name="screen_pinning_positive" msgid="3783985798366751226">"Važi"</string>
+ <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
+ <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li da sakrijete <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
+ <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ovo će se ponovo pojaviti kada ga sledeći put budete uključili u podešavanjima."</string>
+ <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Sakrij"</string>
+ <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> želi da bude dijalog za jačinu zvuka."</string>
+ <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dozvoli"</string>
+ <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
+ <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dijalog za jačinu zvuka"</string>
+ <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da biste vratili original."</string>
+ <string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
+ <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite profil za Work"</string>
+ <string name="system_ui_tuner" msgid="708224127392452018">"Tjuner za korisnički interfejs sistema"</string>
+ <string name="show_battery_percentage" msgid="5444136600512968798">"Prikazuj ugrađeni procenat baterije"</string>
+ <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazivanje nivoa napunjenosti baterije u procentima unutar ikone na statusnoj traci kada se baterija ne puni"</string>
+ <string name="quick_settings" msgid="10042998191725428">"Brza podešavanja"</string>
+ <string name="status_bar" msgid="4877645476959324760">"Statusna traka"</string>
+ <string name="overview" msgid="4018602013895926956">"Pregled"</string>
+ <string name="demo_mode" msgid="2389163018533514619">"Režim demonstracije"</string>
+ <string name="enable_demo_mode" msgid="4844205668718636518">"Omogući režim demonstracije"</string>
+ <string name="show_demo_mode" msgid="2018336697782464029">"Prikaži režim demonstracije"</string>
+ <string name="status_bar_ethernet" msgid="5044290963549500128">"Eternet"</string>
+ <string name="status_bar_alarm" msgid="8536256753575881818">"Alarm"</string>
+ <string name="status_bar_work" msgid="6022553324802866373">"Profil za Work"</string>
+ <string name="status_bar_airplane" msgid="7057575501472249002">"Režim rada u avionu"</string>
+ <string name="add_tile" msgid="2995389510240786221">"Dodaj pločicu"</string>
+ <string name="broadcast_tile" msgid="3894036511763289383">"Pločica za emitovanje"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g> ako ne isključite ovo pre toga"</string>
+ <string name="zen_alarm_warning" msgid="444533119582244293">"Nećete čuti sledeći alarm u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="alarm_template" msgid="3980063409350522735">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="alarm_template_far" msgid="4242179982586714810">"u <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"Brza podešavanja, <xliff:g id="TITLE">%s</xliff:g>."</string>
+ <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Hotspot"</string>
+ <string name="accessibility_managed_profile" msgid="6613641363112584120">"Profil za Work"</string>
+ <string name="tuner_warning_title" msgid="7094689930793031682">"Zabava za neke, ali ne za sve"</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"Tjuner za korisnički interfejs sistema vam pruža dodatne načine za podešavanje i prilagođavanje Android korisničkog interfejsa. Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string>
+ <string name="tuner_persistent_warning" msgid="8597333795565621795">"Ove eksperimentalne funkcije mogu da se promene, otkažu ili nestanu u budućim izdanjima. Budite oprezni."</string>
+ <string name="got_it" msgid="2239653834387972602">"Važi"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"Čestitamo! Tjuner za korisnički interfejs sistema je dodat u Podešavanja"</string>
+ <string name="remove_from_settings" msgid="8389591916603406378">"Ukloni iz Podešavanja"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li da uklonite Tjuner za korisnički interfejs sistema iz Podešavanja i da prestanete da koristite sve njegove funkcije?"</string>
+ <string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na uređaju"</string>
+ <string name="clock_seconds" msgid="7689554147579179507">"Prikazuj sekunde na satu"</string>
+ <string name="clock_seconds_desc" msgid="6282693067130470675">"Sekunde na satu se prikazuju na statusnoj traci. To može da utiče na trajanje baterije."</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi Brza podešavanja"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"Prikaži osvetljenost u Brzim podešavanjima"</string>
+ <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
+ <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
+ <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
+ <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Primeni na obaveštenja o temi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Primeni na sva obaveštenja iz ove aplikacije"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Ova obaveštenja se prikazuju bez zvuka"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Prikazuju se u vrhu liste obaveštenja i emituje se zvuk"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Nakratko se prikazuju na ekranu i emituje se zvuk"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normalne boje"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Izmena boja"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu Brza podešavanja"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu transformaciju"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Primeni"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potvrdite podešavanja"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Neka podešavanja boja mogu da učine uređaj neupotrebljivim. Kliknite na Potvrdi da biste potvrdili ova podešavanja boja, pošto će se u suprotnom ova podešavanja resetovati nakon 10 sekundi."</string>
+</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 91a5c4c..93c26a4 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"търсене"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не можа да стартира."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Още"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"История"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Още <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хоризонтално разделяне"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Вертикално разделяне"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Персонализирано разделяне"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Режимът за запазване на батерията е включен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Намалява ефективността и данните на заден план"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Изключване на режима за запазване на батерията"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Скрито съдържание"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ще започне да заснема всичко, което се показва на екрана ви."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Да не се показва отново"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Изчистване на всички"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Прилагане за известията на тема „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Прилагане за всички известия от това приложение"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Малка важност"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Голяма важност"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Неотложна важност"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Тези известия не се показват"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Беззвучно показване най-долу в списъка с известия"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Тези известия се показват без звук"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Показване най-горе в списъка с известия и издаване на звуков сигнал"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Показване на екрана и издаване на звуков сигнал"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Нормални цветове"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Нощни цветове"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Персонализирани цветове"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестни цветове"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Промяна на цветовете"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показване на плочката за бързи настройки"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Активиране на персонализираното трансформиране"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Прилагане"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потвърждаване на настройките"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Някои настройки за цветовете могат да направят това устройство неизползваемо. За да ги потвърдите, кликнете върху „OK“. В противен случай те ще бъдат нулирани след 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 1c79542..939465b6 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"অনুসন্ধান"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> শুরু করা যায়নি৷"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"আরো"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ইতিহাস"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"আরো <xliff:g id="NUMBER">%d</xliff:g>টি"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"অনুভূমিক স্প্লিট"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"উল্লম্ব স্প্লিট"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"কাস্টম স্প্লিট করুন"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ব্যাটারি সেভার চালু রয়েছে"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"কার্য-সম্পাদনা ও পশ্চাদপট ডেটাকে কমিয়ে দেয়"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ব্যাটারি সঞ্চয়কারী বন্ধ করুন"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"লুকানো বিষয়বস্তু"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> আপনার স্ক্রীনে দেখানো সব কিছু ক্যাপচার করা শুরু করবে।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"আর দেখাবেন না"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"সবকিছু সাফ করুন"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth চালু করবেন?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে Bluetooth চালু করতে হবে।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"চালু করুন"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> বিজ্ঞপ্তিগুলিতে প্রয়োগ করুন"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"এই অ্যাপ্লিকেশনের থেকে সব বিজ্ঞপ্তিতে প্রয়োগ করুন"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"অবরুদ্ধ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"কম গুরুত্ব"</string>
+ <string name="default_importance" msgid="8192107689995742653">"সাধারণ গুরুত্ব"</string>
+ <string name="high_importance" msgid="1527066195614050263">"বেশি গুরুত্ব"</string>
+ <string name="max_importance" msgid="5089005872719563894">"জরুরি গুরুত্ব"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"এই বিজ্ঞপ্তিগুলি কখনোই দেখানো হবে না"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"বিজ্ঞপ্তি তালিকার নীচের অংশে নিঃশব্দে দেখানো হয়"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"স্ক্রীনের উপরে দেখানো হয় এবং শব্দ করে"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
+ <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"স্বাভাবিক রঙ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"রাতের রঙ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"কাস্টম রঙ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"অজানা রঙ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"রঙ সংশোধন"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"দ্রুত সেটিংস টাইল দেখান"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"কাস্টম রূপান্তর সক্ষম করুন"</string>
+ <string name="color_apply" msgid="9212602012641034283">"প্রয়োগ করুন"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"সেটিংস নিশ্চিত করুন"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"কিছু রঙের সেটিংস এই ডিভাইসকে ব্যবহারের অযোগ্য করে দিতে পারে৷ এই রঙের সেটিংস নিশ্চিত করতে ওকে এ ক্লিক করুন, অন্যথায় ১০ সেকেন্ড পরে এই সেটিংস পুনরায় সেট হবে৷"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 1fc41a4..e19aa0e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No s\'ha pogut iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Més"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historial"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> més"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisió horitzontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisió vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisió personalitzada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Estalvi de bateria activat"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Redueix el rendiment i l\'ús de les dades en segon pla."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactiva l\'estalvi de bateria"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contingut amagat"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> començarà a enregistrar tot el que es mostri a la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No ho tornis a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Esborra-ho tot"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplica a les notificacions sobre <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplica a totes les notificacions d\'aquesta aplicació"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloquejades"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importància baixa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importància normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importància alta"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importància urgent"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostris mai aquestes notificacions"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostra de manera silenciosa a la part inferior de la llista de notificacions"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostra aquestes notificacions de manera silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostra a la part superior de la llista de notificacions i emet un so"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostra a la pantalla i emet un so"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Colors normals"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Colors nocturns"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Colors personalitzats"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Colors desconeguts"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificació del color"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra el mosaic de Configuració ràpida"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Activa la transformació personalitzada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplica"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirma la configuració"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algunes opcions de configuració de color poden deixar el dispositiu inservible. Fes clic a D\'acord per confirmar la configuració de color; en cas contrari, la configuració es restablirà al cap de 10 segons."</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index f405f10..b1cd561 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"vyhledat"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikaci <xliff:g id="APP">%s</xliff:g> nelze spustit."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Další"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historie"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"ještě <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vodorovné rozdělení"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikální rozdělení"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Vlastní rozdělení"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Režim Úspora baterie je zapnutý."</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omezuje výkon a data na pozadí"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnout úsporu baterie"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikace <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávat vše, co je zobrazeno na obrazovce."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Tuto zprávu příště nezobrazovat"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Smazat vše"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Použít u oznámení z aplikace <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Použít u všech oznámení z této aplikace"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokováno"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Nízká důležitost"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normální důležitost"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Vysoká důležitost"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgentní důležitost"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Tato oznámení nikdy nezobrazovat"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normální barvy"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Noční barvy"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastní barvy"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznámé barvy"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Změna barev"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobrazit dlaždici Rychlé nastavení"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Umožnit převod na vlastní barvy"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Použít"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Ověření nastavení"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Některá nastavení barev mohou způsobit, že zařízení nebude použitelné. Kliknutím na OK toto nastavení barev potvrdíte, v opačném případě se nastavení po 10 sekundách resetuje."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6e85d8c..2100c57 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"søg"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> kunne ikke startes."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mere"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historik"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> mere"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Opdel vandret"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Opdel lodret"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Opdel brugerdefineret"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparefunktion er slået til"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reducerer ydeevne og baggrundsdata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Deaktiver batterisparefunktion"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Indholdet er skjult"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vil begynde at optage alt, hvad der vises på din skærm."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Vis ikke igen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ryd alt"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Anvend for underretninger vedrørende <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Anvend for alle underretninger fra denne app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokeret"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Lille vigtighed"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normal vigtighed"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Stor vigtighed"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Presserende vigtighed"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Vis aldrig disse underretninger"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Vis lydløst nederst på listen over underretninger"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse underretninger lydløst"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på listen over underretninger, og giv lyd"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Vis på skærmen, og giv lyd"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Almindelige farver"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nattefarver"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Tilpassede farver"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukendte farver"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Farveændring"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis feltet Hurtige indstillinger"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Aktivér tilpasset farveændring"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Anvend"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Bekræft indstillingerne"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Nogle farveindstillinger kan medføre, at du ikke kan bruge enheden. Klik på OK for at bekræfte disse farveindstillinger. Ellers nulstilles disse indstillinger efter ti sekunder."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index cdc1f2a..1ad5b26 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mehr"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Verlauf"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> weitere"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Geteilte Schaltfläche – vertikal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Geteilte Schaltfläche – benutzerdefiniert"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Energiesparmodus ist aktiviert"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Energiesparmodus deaktivieren"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Inhalte ausgeblendet"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf Ihrem Bildschirm angezeigten Aktivitäten auf."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Für Benachrichtigungen über <xliff:g id="TOPIC_NAME">%1$s</xliff:g> anwenden"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Auf alle Benachrichtigungen dieser App anwenden"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blockiert"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Geringe Wichtigkeit"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Reguläre Wichtigkeit"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Hohe Wichtigkeit"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Sehr hohe Wichtigkeit"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Diese Benachrichtigungen niemals anzeigen"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mit Ton ganz oben in der Benachrichtigungsliste anzeigen"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mit Ton auf dem Display einblenden"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Standardfarben"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nachtfarben"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Benutzerdefinierte Farben"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Unbekannte Farben"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Farben ändern"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kachel \"Schnelleinstellungen\" anzeigen"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Benutzerdefinierte Anpassung aktivieren"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Übernehmen"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Einstellungen bestätigen"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Einige Farbeinstellungen können dazu führen, dass das Gerät nicht mehr genutzt werden kann. Klicke auf \"OK\", um diese Farbeinstellungen zu bestätigen. Anderenfalls werden diese Einstellungen in 10 Sekunden zurückgesetzt."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 015eeae..f56d630 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"αναζήτηση"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Δεν ήταν δυνατή η εκκίνηση της εφαρμογής <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Περισσότερα"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Ιστορικό"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ακόμα"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Οριζόντιος διαχωρισμός"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Κάθετος διαχωρισμός"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Προσαρμοσμένος διαχωρισμός"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Η Εξοικονόμηση μπαταρίας είναι ενεργή"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Μειώνει την απόδοση και τα δεδομένα παρασκηνίου"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Απενερ. εξοικ/σης μπαταρίας"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Κρυφό περιεχόμενο"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Θα ξεκινήσει η καταγραφή του περιεχομένου που εμφανίζεται στην οθόνη σας από την εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Να μην εμφανιστεί ξανά"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Διαγραφή όλων"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Να εφαρμοστεί στις ειδοποιήσεις <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Να εφαρμοστεί σε όλες τις ειδοποιήσεις από αυτήν την εφαρμογή"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Μικρής βαρύτητας"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Κανονικής βαρύτητας"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Μεγάλης βαρύτητας"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Επείγουσες"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Να εμφανίζονται στο κάτω τμήμα της λίστας ειδοποιήσεων χωρίς τίτλο"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων με ήχο"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Κανονικά χρώματα"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Νυχτερινά χρώματα"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Προσαρμοσμένα χρώματα"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Άγνωστα χρώματα"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Τροποποίηση χρωμάτων"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Εμφάνιση πλακιδίου Γρήγορων ρυθμίσεων"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ενεργοποίηση προσαρμοσμένου μετασχηματισμού"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Εφαρμογή"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Επιβεβαίωση ρυθμίσεων"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Ορισμένες ρυθμίσεις χρωμάτων μπορεί να μην επιτρέπουν τη χρήση αυτής της συσκευής. Κάντε κλικ στην επιλογή OK για να επιβεβαιώσετε αυτές τις ρυθμίσεις χρωμάτων, διαφορετικά θα γίνει επαναφορά αυτών των ρυθμίσεων μετά από 10 δευτερόλεπτα."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index f3061d72..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"More"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"History"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> More"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
+ <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f3061d72..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"More"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"History"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> More"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
+ <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f3061d72..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"search"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Could not start <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"More"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"History"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> More"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Customised"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Battery saver is on"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduces performance and background data"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Turn off battery saver"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contents hidden"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> will start capturing everything that\'s displayed on your screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Don\'t show again"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Clear all"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Apply to <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Apply to all notifications from this app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blocked"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Low importance"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normal importance"</string>
+ <string name="high_importance" msgid="1527066195614050263">"High importance"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgent importance"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Never show these notifications"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Silently show at the bottom of the notification list"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Unknown colours"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Colour modification"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Show Quick Settings tile"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Enable customised transform"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Apply"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirm Settings"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Some colour settings can make this device unusable. Click OK to confirm these colour settings, otherwise these settings will reset after 10 seconds."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 345b3bf..fd59418 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se pudo iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Más"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historial"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> más"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el uso de datos en segundo plano."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar el ahorro de batería"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comenzará la captura de todo lo que se muestre en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Poca importancia"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar nunca estas notificaciones"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de manera silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificación del color"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar el mosaico de Configuración rápida"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar la transformación personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar la configuración"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden provocar que el dispositivo quede inutilizable. Haz clic en Aceptar para confirmar estos parámetros de color. De lo contrario, la configuración se restablecerá en diez segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index d29eeff..223e684 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"No se ha podido iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Más"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historial"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> más"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"División horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"División vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"División personalizada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ahorro de batería activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce el rendimiento y el envío de datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar ahorro de batería"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contenidos ocultos"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> empezará a capturar todo lo que aparezca en la pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"No volver a mostrar"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Borrar todo"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a las notificaciones de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas las notificaciones de esta aplicación"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Poco importante"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Muy importante"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar estas notificaciones"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de forma silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Colores desconocidos"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificación de colores"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de Ajustes rápidos"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Habilitar transformación personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algunas opciones de configuración de color pueden hacer que el dispositivo no se pueda utilizar. Haz clic en Aceptar para confirmar esta configuración. Si no lo haces, se restablecerá esta configuración cuando transcurran 10 segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 12490b1..f50e78c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"otsing"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Rakendust <xliff:g id="APP">%s</xliff:g> ei saanud käivitada."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Rohkem"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Ajalugu"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Veel <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horisontaalne poolitamine"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikaalne poolitamine"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Kohandatud poolitamine"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akusäästja on sisse lülitatud"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vähendab jõudlust ja taustaandmeid"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akusäästja väljalülitamine"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Sisu on peidetud"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> hakkab jäädvustama kõike, mida ekraanil kuvatakse."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ära kuva uuesti"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tühjenda kõik"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Lülita sisse"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Rakenda teema <xliff:g id="TOPIC_NAME">%1$s</xliff:g> märguannete puhul"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Rakenda selle rakenduse kõigi märguannete puhul"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokeeritud"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Madal tähtsuse tase"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Tavaline tähtsuse tase"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Kõrge tähtsuse tase"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Kiireloomuline tähtsuse tase"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ära kunagi näita neid märguandeid"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Kuva märguannete loendi allosas vaikselt"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Kuva need märguanded vaikselt"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Kuva märguannete loendi ülaosas koos heliga"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Kuva ekraani servas koos heliga"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Tavalised värvid"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Öised värvid"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Kohandatud värvid"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Värvid on teadmata"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Värvi muutmine"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Kuva paan Kiirseaded"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Luba kohandatud teisendamine"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Rakenda"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Seadete kinnitamine"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Mõni värviseade ei saa seadet võib-olla kasutada. Nende värviseadete kinnitamiseks klõpsake OK, muidu lähtestatakse need seaded 10 sekundi pärast."</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 2938bd4..c481f52 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"bilatu"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ezin izan da hasi <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Gehiago"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historia"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Beste <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Bateria aurrezlea aktibatuta dago"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Errendimendua eta atzeko planoko datuak murrizten ditu"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desaktibatu bateria aurrezteko aukera"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Edukiak ezkutatuta daude"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioak pantailan bistaratzen den guztia grabatuko du."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ez erakutsi berriro"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Garbitu guztiak"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplikatu \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\" gaiari buruzko jakinarazpenei"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplikatu aplikazio honetako jakinarazpen guztiei"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Garrantzi txikia"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Garrantzi normala"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Garrantzi handia"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Premiazkoa"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ez erakutsi jakinarazpen hauek inoiz"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Kolore normalak"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Gaueko koloreak"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Kolore pertsonalizatuak"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Kolore ezezagunak"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Kolore-aldaketa"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Erakutsi ezarpen bizkorren lauza"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Gaitu itxuraldaketa pertsonalizatua"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplikatu"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Berretsi ezarpenak"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Baliteke gailua kolore-ezarpen batzuekin ezin erabili izatea. Kolore-ezarpenak berresteko, sakatu Ados. Bestela, hamar segundoren buruan berrezarriko dira ezarpenak."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 20c85ad..3dee7c9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"جستجو"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> شروع نشد."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"بیشتر"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"سابقه"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> مورد دیگر"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"تقسیم افقی"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"تقسیم عمودی"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"سفارشی کردن تقسیم"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"بهینهسازی باتری روشن است."</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"عملکرد و اطلاعات پسزمینه را کاهش میدهد"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"بهینهسازی باتری را خاموش کنید"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی میکند که در صفحهنمایش شما نمایش داده میشود."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"پاک کردن همه موارد"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحهکلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"روشن کردن"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"اعمال بر روی اعلانهای <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"اعمال بر روی تمام اعلانهای این برنامه"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"مسدود شده"</string>
+ <string name="low_importance" msgid="4109929986107147930">"اهمیت کم"</string>
+ <string name="default_importance" msgid="8192107689995742653">"اهمیت معمولی"</string>
+ <string name="high_importance" msgid="1527066195614050263">"اهمیت زیاد"</string>
+ <string name="max_importance" msgid="5089005872719563894">"اهمیت فوری"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"هرگز این اعلانها نشان داده نشوند"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"بدون صدا در پایین فهرست اعلان نشان داده شود"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"این اعلانها بیصدا نشان داده شوند"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"در بالای فهرست اعلانها و به همراه صدا نشان داده شود"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"در جلوی صفحه به همراه صدا نشان داده شود"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
+ <string name="notification_done" msgid="5279426047273930175">"تمام"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"رنگهای عادی"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"رنگهای شب"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"رنگهای سفارشی"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"رنگهای نامشخص"</string>
+ <string name="color_transform" msgid="6985460408079086090">"اصلاح رنگ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"نمایش کاشی تنظیمات سریع"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"فعال کردن تبدیل سفارشی"</string>
+ <string name="color_apply" msgid="9212602012641034283">"اعمال کردن"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"تأیید تنظیمات"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"بعضی از تنظیمات رنگ میتوانند این دستگاه را غیرقابل استفاده کنند. برای تأیید این تنظیمات رنگ روی «تأیید» کلیک کنید، در غیر این صورت این تغییرات بعد از ۱۰ ثانیه بازنشانی میشوند."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index e12c86e..4a5c302 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"haku"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Sovelluksen <xliff:g id="APP">%s</xliff:g> käynnistäminen epäonnistui."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Lisää"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historia"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"+<xliff:g id="NUMBER">%d</xliff:g> lisää"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Vaakasuuntainen jako"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pystysuuntainen jako"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Muokattu jako"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Virransäästö on käytössä"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Rajoittaa suorituskykyä ja taustatiedonsiirtoa"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Poista virransäästö käytöstä"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Sisältö piilotettu"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkaa tallentaa kaiken näytölläsi näkyvän."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Älä näytä uudelleen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Poista kaikki"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Sovella aiheen <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ilmoituksiin"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Sovella kaikkiin tämän sovelluksen ilmoituksiin"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Estetyt"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Ei kovin tärkeä"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Tärkeä"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Hyvin tärkeä"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Kiireellinen"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Älä koskaan näytä näitä ilmoituksia"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Näytä huomaamattomasti ilmoitusluettelon alaosassa"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Näytä nämä ilmoitukset huomaamattomasti"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Näytä ilmoitukset luettelon kärjessä ja toista merkkiääni"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Näytä ilmoitus näytöllä ja toista äänimerkki"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Tavalliset värit"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Yövärit"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Muokatut värit"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Tuntemattomat värit"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Muokatut värit"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Näytä pika-asetusruutu"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ota muokatut värit käyttöön"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Käytä"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Vahvista asetukset"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Jotkin väriasetukset voivat häiritä laitteen käyttöä. Vahvista uudet väriasetukset valitsemalla OK. Muussa tapauksessa aiemmat asetukset palautetaan 10 sekunnin kuluttua."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 63cd500..2a4f4d9 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Plus"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historique"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> autres"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"La fonction Économie d\'énergie est activée"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Réduire les performances et de fond"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur d\'énergie"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> commencer à enregistrer tout ce qui s\'affiche sur votre écran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer à <xliff:g id="TOPIC_NAME">%1$s</xliff:g> notifications"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloquée"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importance urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Afficher en mode silencieux au bas de la liste de notifications"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modifier la couleur"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmer les paramètres"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur « OK » pour valider ces paramètres, sinon ils seront réinitialisés après 10 secondes."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 04ba842..928a8b3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"rechercher"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossible de lancer <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Plus"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historique"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> autres"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Séparation horizontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Séparation verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Séparation personnalisée"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"L\'économiseur de batterie est activé"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Limite les performances et les données en arrière-plan."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Désactiver l\'économiseur de batterie"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contenus masqués"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va commencer à capturer tous les contenus affichés à l\'écran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne plus afficher"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tout effacer"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Appliquer aux notifications relatives au sujet \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Appliquer à toutes les notifications de cette application"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloquées"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgent"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Afficher au bas de la liste des notifications en mode silencieux"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Couleurs inconnues"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modification des couleurs"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afficher la tuile de configuration rapide"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Activer la transformation personnalisée"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Appliquer"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Vérifier les paramètres"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Certains paramètres de couleurs peuvent rendre cet appareil inutilisable. Cliquez sur \"OK\" pour valider ces paramètres, sans quoi ils seront réinitialisés après 10 secondes."</string>
</resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 87753d1..2a951f7 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"buscar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Non foi posible iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Máis"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historial"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> máis"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dividir en horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dividir en vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dividir de xeito personalizado"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"O aforro de batería está activado"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce o rendemento e os datos en segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desactivar o aforro de batería"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contido oculto"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comezará a capturar todo o que apareza na túa pantalla."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrar outra vez"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Eliminar todas"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar ás notificacións de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificacións procedentes desta aplicación"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importancia baixa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importancia urxente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrar nunca estas notificacións"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificacións de forma silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificacións e emitir son"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar na pantalla e emitir son"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Cores nocturnas"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores descoñecidas"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificación de cor"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar mosaico de configuración rápida"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Activar transformación personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configuración"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algunhas opcións de configuración de cor poden facer que este dispositivo sexa inutilizable. Fai clic en Aceptar para confirmar esta configuración de cor; en caso contrario, a configuración restablecerase tras 10 segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index a10f0d5..f331ef9 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"શોધ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> પ્રારંભ કરી શકાયું નથી."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"વધુ"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ઇતિહાસ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> વધુ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"આડું વિભક્ત કરો"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ઊભું વિભક્ત કરો"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"કસ્ટમ વિભક્ત કરો"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"બેટરી સેવર ચાલુ છે"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"પ્રદર્શન અને પૃષ્ઠભૂમિ ડેટા ઘટાડે છે"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"બૅટરી સેવર બંધ કરો"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"સામગ્રીઓ છુપાવેલ છે"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> તમારી સ્ક્રીન પર જે પ્રદર્શિત થાય છે તે દરેક વસ્તુને કેપ્ચર કરવાનું પ્રારંભ કરશે."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ફરીથી બતાવશો નહીં"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"બધુ સાફ કરો"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ચાલુ કરો"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> સૂચનાઓ પર લાગુ કરો"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"આ ઍપ્લિકેશનની તમામ સૂચનાઓ પર લાગુ કરો"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"અવરોધિત"</string>
+ <string name="low_importance" msgid="4109929986107147930">"નિમ્ન મહત્વની"</string>
+ <string name="default_importance" msgid="8192107689995742653">"સામાન્ય મહત્વની"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ઉચ્ચ મહત્વની"</string>
+ <string name="max_importance" msgid="5089005872719563894">"તાત્કાલિક મહત્વની"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"આ સૂચનાઓ ક્યારેય બતાવશો નહીં"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"સૂચનાની સૂચિની નીચે ચુપચાપ બતાવો"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
+ <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"સામાન્ય રંગો"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"રાત્રિ રંગો"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"કસ્ટમ રંગો"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"અજાણ્યા રંગો"</string>
+ <string name="color_transform" msgid="6985460408079086090">"રંગ સંશોધન"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ઝડપી સેટિંગ્સ ટાઇલ બતાવો"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"કસ્ટમ રૂપાંતરણને સક્ષમ કરો"</string>
+ <string name="color_apply" msgid="9212602012641034283">"લાગુ કરો"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"સેટિંગ્સની પુષ્ટિ કરો"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"કેટલીક રંગ સેટિંગ્સ આ ઉપકરણને બિનઉપયોગી બનાવી શકે છે. આ રંગ સેટિંગ્સની પુષ્ટિ કરવા માટે ઑકે ક્લિક કરો, અન્યથા 10 સેકંડ પછી આ સેટિંગ્સ ફરીથી સેટ થશે."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a3c8958..b31c1e0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोज"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ नहीं किया जा सका."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"अधिक"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"इतिहास"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> अधिक"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज रूप से विभाजित करें"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"लम्बवत रूप से विभाजित करें"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"कस्टम रूप से विभाजित करें"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"बैटरी सेवर चालू है"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"निष्पादन और पृष्ठभूमि डेटा को कम करता है"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"बैटरी बचतकर्ता को बंद करें"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"छिपी हुई सामग्री"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपके स्क्रीन पर प्रदर्शित प्रत्येक सामग्री को कैप्चर करना प्रारंभ कर देगी."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"फिर से न दिखाएं"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सभी साफ करें"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करें"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> नोटिफिकेशन पर लागू करें"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"इस ऐप के सभी नोटिफिकेशन पर लागू करें"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"अवरोधित"</string>
+ <string name="low_importance" msgid="4109929986107147930">"निम्न महत्व"</string>
+ <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्व"</string>
+ <string name="high_importance" msgid="1527066195614050263">"उच्च महत्व"</string>
+ <string name="max_importance" msgid="5089005872719563894">"तत्काल महत्व"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ये नोटिफिकेशन कभी ना दिखाएं"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"नोटिफिकेशन सूची में सबसे नीचे मौन रूप से दिखाएं"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"नोटिफिकेशन सूची में सबसे ऊपर दिखाएं और ध्वनि चलाएं"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रीन पर एक झलक दिखाएं और ध्वनि चलाएं"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
+ <string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"रात्रि के रंग"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"कस्टम रंग"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
+ <string name="color_transform" msgid="6985460408079086090">"रंग परिवर्तन"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"त्वरित-सेटिंग टाइल दिखाएं"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"कस्टम रूपांतरण सक्षम करें"</string>
+ <string name="color_apply" msgid="9212602012641034283">"लागू करें"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"सेेटिंग की पुष्टि करें"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"कुछ रंग सेटिंग इस डिवाइस को अनुपयोगी बना सकती हैं. इन रंग सेटिंग की पुष्टि करने के लिए ठीक क्लिक करें, अन्यथा 10 सेकंड के बाद ये सेटिंग रीसेट हो जाएंगी."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 0e171ea..3bef6e9 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -302,7 +302,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pretraži"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacija <xliff:g id="APP">%s</xliff:g> nije pokrenuta."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Više"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Povijest"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Još <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podijeli vodoravno"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podijeli okomito"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podijeli prilagođeno"</string>
@@ -365,7 +365,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Štednja baterije je uključena"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Smanjuje količinu rada i pozadinske podatke"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Isključi uštedu baterije"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Sadržaj je skriven"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> počet će snimati sve što se prikazuje na zaslonu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne prikazuj ponovo"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši sve"</string>
@@ -450,4 +449,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Primijeni na obavijesti za temu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Primijeni na sve obavijesti ove aplikacije"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Hitno"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikad ne prikazuj te obavijesti"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži tiho pri dnu popisa obavijesti"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži te obavijesti tiho"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Prikaži na zaslonu i emitiraj zvučni signal"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Uobičajene boje"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Nepoznate boje"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Izmjena boja"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaži pločicu s brzim postavkama"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Omogući prilagođenu preobrazbu"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Primijeni"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potvrdite postavke"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Neke postavke boja mogu učiniti uređaj neupotrebljivim. Kliknite U redu da biste potvrdili postavke boja jer će se u suprotnom poništiti za 10 sekundi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 39336c8..8dc9a19 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"keresés"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nem lehet elindítani a következőt: <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Továbbiak"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Előzmények"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> további"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Osztott vízszintes"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Osztott függőleges"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Osztott egyéni"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akkumulátorkímélő mód bekapcsolva"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Csökkenti a teljesítményt és a háttéradatok használatát"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Akkumulátorkímélő mód kikapcsolása"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Tartalom elrejtve"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"A(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> alkalmazás rögzíteni fog mindent, ami megjelenik a képernyőn."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ne jelenjen meg többé"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Az összes törlése"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bekapcsolás"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"A következő értesítések esetén: <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Az alkalmazás minden értesítése esetén"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Letiltva"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Kevésbé fontos"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normál"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Fontos"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Sürgős"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Soha nem jelennek meg ezek az értesítések"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Hangjelzés nélkül jelennek meg az értesítési lista alján"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Hang nélkül jelennek meg ezek az értesítések"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Az értesítési lista tetején jelennek meg hangjelzéssel"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Kész"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Hagyományos színek"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Esti színek"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Egyéni színek"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Ismeretlen színek"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Színmódosítás"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Gyorsbeállítások mozaikjának megjelenítése"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Egyéni átalakítás engedélyezése"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Alkalmaz"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Beállítások megerősítése"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Bizonyos színbeállítások használhatatlanná tehetik ezt az eszközt. A színbeállítás megerősítéséhez kattintson az OK lehetőségre, máskülönben a rendszer 10 másodpercen belül visszaáll a korábbira."</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 0d50b9c..99d6980 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"որոնել"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Հնարավոր չէ գործարկել <xliff:g id="APP">%s</xliff:g>-ը:"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Ավելին"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Պատմություն"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"ևս <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Հորիզոնական տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ուղղահայաց տրոհում"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Հատուկ տրոհում"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Մարտկոցի տնտեսումը միացված է"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Նվազեցնում է ծանրաբեռնվածությունը և ֆոնային տվյալները"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Անջատել մարտկոցի տնտեսումը"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Բովանդակությունը թաքցված է"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ծրագիրը կսկսի հավաքագրել այն ամենն ինչ ցուցադրվում է ձեր էկրանին:"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Այլևս ցույց չտալ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Մաքրել բոլորը"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Կիրառել <xliff:g id="TOPIC_NAME">%1$s</xliff:g>-ի ծանուցումների նկատմամբ"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Կիրառել այս հավելվածի բոլոր ծանուցումների նկատմամբ"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Ցածր կարևորություն"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Սովորական կարևորություն"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Բարձր կարևորություն"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Հրատապ կարևորություն"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Երբեք չցուցադրել այս ծանուցումները"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Սովորական գույներ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Գիշերային գույներ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Հատուկ գույներ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Անհայտ գույներ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Գույնի փոփոխում"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ցույց տալ Արագ կարգավորումների սալիկը"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Միացնել հատուկ գունային անցումը"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Կիրառել"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Հաստատել կարգավորումները"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Գունային որոշ կարգավորումները կարող են այս սարքը օգտագործման համար ոչ պիտանի դարձնել: Սեղմեք Լավ կոճակը՝ գունային այս կարգավորումները հաստատելու համար: Հակառակ դեպքում այս կարգավորումները կվերակայվեն 10 վայրկյան հետո:"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 7ec4685..f6124db 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"telusuri"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulai <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Lainnya"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Riwayat"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Lagi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Pisahkan Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Pisahkan Vertikal"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pisahkan Khusus"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Penghemat baterai aktif"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangi kinerja dan data latar belakang"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Nonaktifkan penghemat baterai"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Konten tersembunyi"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mulai menangkap apa saja yang ditampilkan pada layar Anda."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tampilkan lagi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hapus semua"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Terapkan ke notifikasi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Terapkan untuk semua notifikasi dari aplikasi ini"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Tingkat kepentingan: rendah"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Tingkat kepentingan: normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Tingkat kepentingan: tinggi"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Tingkat kepentingan: darurat"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah tunjukkan notifikasi ini"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan di bawah daftar notifikasi tanpa suara"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan notifikasi ini tanpa suara"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan di bagian atas daftar notifikasi dan bunyikan suara"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Muncul di layar dan bunyikan suara"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Warna normal"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Warna khusus"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Perubahan warna"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tampilkan ubin Setelan Cepat"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Aktifkan transformasi khusus"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Terapkan"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Konfirmasi setelan"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Beberapa setelan warna dapat membuat perangkat ini tidak dapat digunakan. Klik OKE untuk mengonfirmasi setelan warna ini. Jika tidak, setelan ini akan disetel ulang setelah 10 detik."</string>
</resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index c17e174..7ea1746 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"leita"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ekki var hægt að ræsa <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Meira"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Ferill"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> í viðbót"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Lárétt skipting"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Lóðrétt skipting"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Sérsniðin skipting"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kveikt er á rafhlöðusparnaði"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Dregur úr afköstum og bakgrunnsgögnum"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slökkva á rafhlöðusparnaði"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Innihald falið"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mun fanga allt sem birtist á skjánum."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ekki sýna þetta aftur"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Hreinsa allt"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Láta gilda um tilkynningar varðandi <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Láta gilda um allar tilkynningar frá þessu forriti"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Útilokuð"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Ekki svo mikilvægt"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Venjulegt mikilvægi"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Mjög mikilvægt"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Afar áríðandi"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldrei sýna þessar tilkynningar"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Sýna þessar tilkynningar án hljóðs"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Sýna efst á tilkynningalistanum og spila hljóð"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Birta á skjánum og spila hljóð"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Venjulegir litir"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Næturlitir"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Sérsniðnir litir"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Óþekktir litir"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Litabreytingar"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Sýna flísar í flýtistillingum"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Kveikja á sérsniðinni umbreytingu"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Nota"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Staðfesta stillingar"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Sumar litastillingar kunna að bitna á notagildi tækisins. Veldu „Í lagi“ til að staðfesta þessar litastillingar, að öðrum kosti verða litirnir endurstilltir eftir tíu sekúndur."</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 866f872..b395f8b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cerca"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Impossibile avviare <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Altro"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Cronologia"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Altre attività: <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisione in orizzontale"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisione in verticale"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisione personalizzata"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inizierà ad acquisire tutto ciò che è visualizzato sul tuo schermo."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Non mostrare più"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Cancella tutto"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Applica a notifiche <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Applica a tutte le notifiche di quest\'app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloccata"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importanza scarsa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importanza normale"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importanza elevata"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importanza urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrare mai queste notifiche"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostra silenziosamente nella parte inferiore dell\'elenco delle notifiche"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostra silenziosamente queste notifiche"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostra nella parte superiore dell\'elenco delle notifiche e riproduci suono"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Apri sullo schermo e riproduci suono"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Colori normali"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Colori per la notte"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Colori personalizzati"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Colori sconosciuti"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modifica del colore"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostra il riquadro Impostazioni rapide"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Attiva la trasformazione personalizzata"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Applica"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Conferma le impostazioni"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Alcune impostazioni relative ai colori potrebbero rendere inutilizzabile il dispositivo. Fai clic su OK per confermare queste impostazioni; in caso contrario, le impostazioni verranno reimpostate dopo 10 secondi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 8d3da117..2c894f5 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"חפש"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"לא ניתן היה להפעיל את <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"עוד"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"היסטוריה"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> נוספות"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"פיצול אופקי"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"פיצול אנכי"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"פיצול מותאם אישית"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"תכונת \'חיסכון בסוללה\' פועלת"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"מפחית את הביצועים ונתונים ברקע"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"כבה את החיסכון בסוללה"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"התוכן מוסתר"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> יתחיל להקליט את כל התוכן המוצג במסך שלך."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"אל תציג שוב"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"נקה הכל"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"האם להפעיל את ה-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"החל על הודעות של <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"החל על כל ההודעות מאפליקציה זו"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"חסום"</string>
+ <string name="low_importance" msgid="4109929986107147930">"חשיבות נמוכה"</string>
+ <string name="default_importance" msgid="8192107689995742653">"חשיבות רגילה"</string>
+ <string name="high_importance" msgid="1527066195614050263">"חשיבות גבוהה"</string>
+ <string name="max_importance" msgid="5089005872719563894">"חשיבות דחופה"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"לעולם אל תציג את ההודעות האלה"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"הצג בחלק התחתון של רשימת ההודעות בלי להשמיע צליל"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"הצג בחלק העליון של רשימת ההודעות והשמע צליל"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"הצג לרגע על המסך והשמע צליל"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
+ <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"צבעים רגילים"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"צבעי לילה"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"צבעים מותאמים אישית"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"צבעים לא ידועים"</string>
+ <string name="color_transform" msgid="6985460408079086090">"שינוי צבע"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"הצגת אריח של הגדרות מהירות"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"הפעל טרנספורמציה מותאמת אישית"</string>
+ <string name="color_apply" msgid="9212602012641034283">"החל"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index ae57a32..580d995 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"検索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>を開始できません。"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"もっと見る"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"履歴"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"他 <xliff:g id="NUMBER">%d</xliff:g> 件"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"横に分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"縦に分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"分割(カスタム)"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"バッテリーセーバーがON"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"パフォーマンスとバックグラウンドデータを制限します"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"バッテリーセーバーをOFFにします"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"コンテンツが非表示"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>で、画面に表示されているコンテンツのキャプチャを開始します。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"次回から表示しない"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"すべて消去"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」の通知に適用"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"このアプリからのすべての通知に適用"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ブロック中"</string>
+ <string name="low_importance" msgid="4109929986107147930">"重要度: 低"</string>
+ <string name="default_importance" msgid="8192107689995742653">"重要度: 中"</string>
+ <string name="high_importance" msgid="1527066195614050263">"重要度: 高"</string>
+ <string name="max_importance" msgid="5089005872719563894">"重要度: 緊急"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"今後はこの通知を表示しない"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"通知リストの末尾にマナーモードで表示する"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"この通知をマナーモードで表示する"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"通知リストの先頭に表示し、音声でも知らせる"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"画面に数秒間表示し、音声でも知らせる"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
+ <string name="notification_done" msgid="5279426047273930175">"完了"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"標準の色"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"夜間の色"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"カスタムの色"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"不明な色"</string>
+ <string name="color_transform" msgid="6985460408079086090">"色の変更"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"[クイック設定] タイルの表示"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"カスタム変換の有効化"</string>
+ <string name="color_apply" msgid="9212602012641034283">"適用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"設定の確認"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"一部の色設定を適用すると、この端末を使用できなくなることがあります。この色設定を確認するには、[OK] をクリックしてください。確認しない場合、10 秒後に設定はリセットされます。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 18d6f16..7a51668 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ძიება"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-ის გამოძახება ვერ მოხერხდა."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"მეტი"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ისტორია"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"კიდევ <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ჰორიზონტალური გაყოფა"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ვერტიკალური გაყოფა"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ინდივიდუალური გაყობა"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ბატარეის დამზოგი ჩართულია"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ამცირებს წარმადობას და უკანა ფონის მონაცემებს"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ბატარეის დაზოგვის გამორთვა"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"შიგთავსი დამალულია"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> დაიწყებს იმ ყველაფრის აღბეჭდვას, რაც თქვენს ეკრანზე ჩანს."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"აღარ მაჩვენო"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ყველას გასუფთავება"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"„<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ ტიპის შეტყობინებებისთვის მისადაგება"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ამ აპის ყველა შეტყობინებისთვის მისადაგება"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</string>
+ <string name="low_importance" msgid="4109929986107147930">"დაბალი პრიორიტეტი"</string>
+ <string name="default_importance" msgid="8192107689995742653">"ჩვეულებრივი პრიორიტეტი"</string>
+ <string name="high_importance" msgid="1527066195614050263">"მაღალი პრიორიტეტი"</string>
+ <string name="max_importance" msgid="5089005872719563894">"გადაუდებელი"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ამ შეტყობინებების ჩვენების შეწყვეტა"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"ამ შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"ამ შეტყობინებების სიის თავში, ხმოვან სიგნალთან ერთად ჩვენება"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ამ შეტყობინებების პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად ჩვენება"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
+ <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ჩვეულებრივი ფერები"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ღამის ფერები"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"მორგებული ფერები"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"უცნობი ფერები"</string>
+ <string name="color_transform" msgid="6985460408079086090">"ფერების შეცვლა"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"სწრაფი პარამეტრების მოზაიკის ჩვენება"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"მორგებული გარდაქმნის ჩართვა"</string>
+ <string name="color_apply" msgid="9212602012641034283">"გამოყენება"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"პარამეტრების დადასტურება"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ფერთა ზოგიერთ პარამეტრს ამ მოწყობილობასთან მუშაობის გართულება შეუძლია. ფერთა ამჟამინდელი პარამეტრების დასადასტურებლად, დააწკაპუნეთ „კარგი“-ზე. წინააღმდეგ შემთხვევაში, პარამეტრები 10 წამის შემდეგ ჩამოიყრება."</string>
</resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 0d4b618..eb8995e 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"іздеу"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> іске қосу мүмкін болмады."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Қосымша"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Тарих"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Қосымша"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Бөлінген көлденең"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Бөлінген тік"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Бөлінген теңшелетін"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батарея үнемдегіш қосулы"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Өнімділікті және фондық деректерді азайтады"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батарея үнемдегішті өшіру"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмұн жасырылған"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранда көрсетілгеннің барлығын түсіре бастайды."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Қайта көрсетпеу"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Барлығын тазалау"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> хабарландыруға қолдану"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Осы қолданбаның барлық хабарландыруларына қолдану"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Бөгелген"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Төмен маңыздылық"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Қалыпты маңыздылық"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Жоғары маңыздылық"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Шұғыл маңыздылық"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Осы хабарландыруларды ешқашан көрсетпеу"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Осы хабарландыруларды үнсіз көрсету"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Хабарландыруларды тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Экранға бекіту және дыбыс шығару"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Қалыпты түстер"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Түнгі түстер"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Арнаулы түстер"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгісіз түстер"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Түсті өзгерту"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Жылдам параметрлер торын көрсету"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Арнаулы түрлендіруді қосу"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Қолдану"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
</resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 8a72493..5c10213 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ស្វែងរក"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"មិនអាចចាប់ផ្ដើម <xliff:g id="APP">%s</xliff:g> ទេ។"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"ច្រើនទៀត"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ប្រវត្តិ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ទៀត"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"បំបែកផ្តេក"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"បំបែកបញ្ឈរ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"បំបែកផ្ទាល់ខ្លួន"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"កម្មវិធីសន្សំថ្មគឺបើក"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ការបន្ថយការប្រតិបត្តិ និងទិន្នន័យផ្ទៃខាងក្រោយ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"បិទធាតុរក្សាថាមពលថ្ម"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"បានលាក់មាតិកា"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> នឹងចាប់ផ្ដើមចាប់យកអ្វីៗគ្រប់យ៉ាងដែលបង្ហាញលើអេក្រង់របស់អ្នក។"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"កុំបង្ហាញម្ដងទៀត"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"សម្អាតទាំងអស់"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"បើក"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"អនុវត្តចំពោះការជូនដំណឹង <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"អនុវត្តចំពោះការជូនដំណឹងទាំងអស់ពីកម្មវិធីនេះ"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"បានរារាំង"</string>
+ <string name="low_importance" msgid="4109929986107147930">"មិនសូវសំខាន់"</string>
+ <string name="default_importance" msgid="8192107689995742653">"សំខាន់មធ្យម"</string>
+ <string name="high_importance" msgid="1527066195614050263">"សំខាន់ខ្លាំង"</string>
+ <string name="max_importance" msgid="5089005872719563894">"សំខាន់ជាបន្ទាន់"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"កុំបង្ហាញការជូនដំណឹងទាំងនេះ"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"បង្ហាញស្ងាត់ៗនៅផ្នែកខាងក្រោមបញ្ជីនៃការជូនដំណឹង"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
+ <string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ពណ៌ធម្មតា"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ពណ៌ពេលយប់"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ពណ៌ផ្ទាល់ខ្លួន"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"ពណ៌មិនស្គាល់"</string>
+ <string name="color_transform" msgid="6985460408079086090">"ការកែសម្រួលពណ៌"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"បង្ហាញផ្ទាំងប្រអប់ការកំណត់រហ័ស"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"បើកដំណើរការផ្លាស់ប្តូរផ្ទាល់ខ្លួន"</string>
+ <string name="color_apply" msgid="9212602012641034283">"អនុវត្ត"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"បញ្ជាក់ការកំណត់"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ការកំណត់ពណ៌មួយចំនួនអាចធ្វើឲ្យឧបករណ៍នេះមិនអាចប្រើបាន។ សូមចុច យល់ព្រម ដើម្បីបញ្ជាក់ការកំណត់ពណ៌ទាំងនេះ បើមិនដូច្នេះទេការកំណត់ទាំងនេះនឹងកំណត់ឡើងវិញក្នុងរយៈពេល 10 វិនាទីបន្ទាប់។"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index d20f0394..28b2de5 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ಹುಡುಕಾಟ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ಪ್ರಾರಂಭಿಸಲು ಸಾದ್ಯವಿಲ್ಲ."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"ಇನ್ನಷ್ಟು"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ಇತಿಹಾಸ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ಇನ್ನಷ್ಟು"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ಅಡ್ಡಲಾಗಿ ವಿಭಜಿಸಿದ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ಲಂಬವಾಗಿ ವಿಭಜಿಸಿದ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ಕಸ್ಟಮ್ ವಿಭಜಿಸಿದ"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ಬ್ಯಾಟರಿ ರಕ್ಷಕ ಆನ್ ಆಗಿದೆ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ಕಾರ್ಯಕ್ಷಮತೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆಫ್ ಮಾಡಿ"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"ವಿಷಯಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"ನಿಮ್ಮ ಪರದೆಯ ಮೇಲೆ ಪ್ರದರ್ಶಿಸಲಾಗುವ ಎಲ್ಲವನ್ನೂ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಯು ಸೆರೆಹಿಡಿಯಲು ಪ್ರಾರಂಭಿಸುತ್ತದೆ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸದಿರು"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸು"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ಆನ್ ಮಾಡು"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ಈ ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳಿಗೆ ಅನ್ವಯಿಸಿ"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"ಕಡಿಮೆ ಪ್ರಾಮುಖ್ಯತೆ"</string>
+ <string name="default_importance" msgid="8192107689995742653">"ಸಾಮಾನ್ಯ ಪ್ರಾಮುಖ್ಯತೆ"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ಉನ್ನತ ಪ್ರಾಮುಖ್ಯತೆ"</string>
+ <string name="max_importance" msgid="5089005872719563894">"ತುರ್ತು ಪ್ರಾಮುಖ್ಯತೆ"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಎಂದಿಗೂ ತೋರಿಸಬೇಡ"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯ ಕೆಳಭಾಗದಲ್ಲಿ ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ಸಾಮಾನ್ಯ ಬಣ್ಣಗಳು"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ರಾತ್ರಿ ಬಣ್ಣಗಳು"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ಕಸ್ಟಮ್ ಬಣ್ಣಗಳು"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"ಅಪರಿಚಿತ ಬಣ್ಣಗಳು"</string>
+ <string name="color_transform" msgid="6985460408079086090">"ಬಣ್ಣ ಬದಲಾವಣೆ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳ ಟೈಲ್ ತೋರಿಸು"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"ಕಸ್ಟಮ್ ಪರಿವರ್ತನೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ಅನ್ವಯಿಸು"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಖಚಿತಪಡಿಸಿ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ಕೆಲವು ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್ಗಳು ಈ ಸಾಧನವನ್ನು ಅನುಪಯುಕ್ತಗೊಳಿಸಬಹುದು. ಈ ಬಣ್ಣ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಖಚಿತಪಡಿಸಲು ಸರಿ ಕ್ಲಿಕ್ ಮಾಡಿ, ಇಲ್ಲವಾದರೆ ಈ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು 10 ಸೆಕೆಂಡುಗಳ ನಂತರ ಮರುಹೊಂದಿಸಿ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 2d61eab..110376f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"검색"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>을(를) 시작할 수 없습니다."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"더보기"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"기록"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g>개 더보기"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"수평 분할"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"수직 분할"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"맞춤 분할"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"배터리 세이버 사용 중"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"성능 및 백그라운드 데이터를 줄입니다."</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"배터리 절약 기능 사용 중지"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"숨겨진 콘텐츠"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>에서 화면에 표시된 모든 것을 캡처하기 시작합니다."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"다시 표시 안함"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"모두 지우기"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"사용"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> 알림에 적용"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"이 앱의 전체 알림에 적용"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"차단됨"</string>
+ <string name="low_importance" msgid="4109929986107147930">"중요도 낮음"</string>
+ <string name="default_importance" msgid="8192107689995742653">"중요도 보통"</string>
+ <string name="high_importance" msgid="1527066195614050263">"중요도 높음"</string>
+ <string name="max_importance" msgid="5089005872719563894">"중요도 긴급"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"알림 다시 표시 안함"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"알림 목록 하단에 무음으로 표시"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"무음으로 알림 표시"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"알림 목록 상단에 표시하고 소리로 알림"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"화면에 표시하고 소리로 알림"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
+ <string name="notification_done" msgid="5279426047273930175">"완료"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"일반 색상"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"야간 색상"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"맞춤 색상"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"알 수 없는 색상"</string>
+ <string name="color_transform" msgid="6985460408079086090">"색상 수정"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"빠른 설정 타일 표시"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"맞춤 변환 사용"</string>
+ <string name="color_apply" msgid="9212602012641034283">"적용"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"설정 확인"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"일부 색상 설정으로 인해 이 기기를 사용하지 못할 수 있습니다. 확인을 클릭하여 이러한 색상 설정을 확인하지 않으면 10초 후에 설정이 초기화됩니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 6d624d1..ee2ef5d 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"издөө"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> баштай алган жок."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Дагы"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Таржымал"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Дагы <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батареяны үнөмдөгүч күйгүзүлдү"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Иштин майнаптуулугун начарлатып, фондук дайындарды чектейт"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батареянын кубатын үнөмдөгүчтү өчүрүп коюу"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Мазмундар жашырылган"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экранга чыккан нерсенин баарын сүрөткө тарта баштайт."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Экинчи көрсөтүлбөсүн"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Бардыгын тазалап салуу"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> эскертмелерине колдонулсун"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Ушул колдонмодон алынган бардык эскертмелерге колдонулсун"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Маанилүүлүгү төмөн"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Маанилүүлүгү орточо"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Маанилүүлүгү жогору"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Маанилүүлүгү шашылыш"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Эскертмелер тизмесинин эң ылдыйында үнсүз көрсөтүлсүн"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Үн менен коштолуп, экранга чыгарылсын"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Кадимки түстөр"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Түнкү түстөр"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Ыңгайлаштырылган түстөр"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Белгисиз түстөр"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Түсүн өзгөртүү"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ыкчам жөндөөлөр тактасын көрсөтүү"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ыңгайлаштырылган өзгөртүүнү иштетүү"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
</resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 456391d..c75a89f 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,5 +24,5 @@
<integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
<dimen name="docked_divider_handle_width">2dp</dimen>
- <dimen name="docked_divider_handle_height">24dp</dimen>
+ <dimen name="docked_divider_handle_height">16dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index 96d8fb8..b711faa 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -20,7 +20,7 @@
</style>
<style name="DockedDividerBackground">
- <item name="android:layout_width">12dp</item>
+ <item name="android:layout_width">10dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center_horizontal</item>
</style>
@@ -28,7 +28,7 @@
<style name="DockedDividerHandle">
<item name="android:layout_gravity">center_vertical</item>
<item name="android:layout_width">48dp</item>
- <item name="android:layout_height">64dp</item>
+ <item name="android:layout_height">96dp</item>
</style>
</resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 35a6e1b..ed103ea 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ຊອກຫາ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ບໍ່ສາມາດເລີ່ມ <xliff:g id="APP">%s</xliff:g> ໄດ້."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"ເພີ່ມເຕີມ"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ປະຫວັດ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ເພີ່ມເຕີມ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ການແຍກລວງຂວາງ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ການແຍກລວງຕັ້ງ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ການແຍກກຳນົດເອງ"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ເປີດໃຊ້ໂຕປະຢັດແບັດເຕີຣີແລ້ວ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ຫຼຸດປະສິທິພາບແລະການນຳໃຊ້ຂໍ້ມູນພື້ນຫຼັງ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ປິດໂຕປະຢັດແບັດເຕີຣີ"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"ເນື້ອຫາຖືກເຊື່ອງໄວ້"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ຈະເລີ່ມບັນທຶກທຸກຢ່າງທີ່ສະແດງຜົນໃນໜ້າຈໍທ່ານ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ລຶບລ້າງທັງໝົດ"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດໃຊ້ Bluetooth ບໍ່?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອເຊື່ອມຕໍ່ແປ້ນພິມຂອງທ່ານກັບແທັບເລັດຂອງທ່ານ, ກ່ອນອື່ນໝົດທ່ານຕ້ອງເປີດ Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ເປີດ"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"ນຳໃຊ້ກັບການແຈ້ງເຕືອນ <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ນຳໃຊ້ກັບທຸກການແຈ້ງເຕືອນຈາກແອັບນີ້"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ບລັອກໄວ້ແລ້ວ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"ຄວາມສໍາຄັນຕໍ່າ"</string>
+ <string name="default_importance" msgid="8192107689995742653">"ຄວາມສຳຄັນປົກກະຕິ"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ຄວາມສໍາຄັນສູງ"</string>
+ <string name="max_importance" msgid="5089005872719563894">"ຄວາມສໍາຄັນຮີບດ່ວນ"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ຢ່າສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"ສະແດງຢູ່ສ່ວນລຸ່ມຂອງລາຍການແຈ້ງເຕືອນແບບມີບໍ່ສຽງ"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"ການຕັ້ງຄ່າເພີ່ມເຕີມ"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ສີປົກກະຕິ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ສີຕອນກາງຄືນ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ສີແບບກຳນົດເອງ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"ສີທີ່ບໍ່ຮູ້ຈັກ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"ການດັດແປງສີ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ສະແດງໄທລ໌ການຕັ້ງຄ່າດ່ວນ"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"ເປີດໃຊ້ການປ່ຽນສີແບບກຳນົດເອງ"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ນຳໃຊ້"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ຢືນຢັນການຕັ້ງຄ່າ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ບາງການຕັ້ງຄ່າສີສາມາດເຮັດໃຫ້ອຸປະກອນນີ້ບໍ່ສາມາດໃຊ້ໄດ້. ຄລິກ ຕົກລົງ ເພື່ອຢືນຢັນການຕັ້ງຄ່າສີເຫຼົ່ານີ້, ຖ້າບໍ່ດັ່ງນັ້ນ ການຕັ້ງຄ່າເຫຼົ່ານີ້ຈະຕັ້ງຄືນໃໝ່ ຫຼັງຈາກ 10 ວິນາທີ."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 43d5f06..ba98e2b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"paieška"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nepavyko paleisti <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Daugiau"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Istorija"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Dar <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontalus skaidymas"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikalus skaidymas"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tinkintas skaidymas"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Akumuliatoriaus tausojimo priemonė įjungta"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sumažinamas našumas ir foninių duomenų naudojimas"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Išjungti Akumuliatoriaus tausojimo priemonę"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Turinys paslėptas"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"„<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ pradės fiksuoti viską, kas rodoma jūsų ekrane."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Daugiau neberodyti"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Viską išvalyti"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Taikyti „<xliff:g id="TOPIC_NAME">%1$s</xliff:g>“ pranešimams"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Taikyti visiems pranešimams iš šios programos"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Užblokuota"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Maža svarba"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Įprasta svarba"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Didelė svarba"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Skubi svarba"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Niekada nerodyti šių pranešimų"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tyliai rodyti šiuos pranešimus"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Rodyti pranešimų sąrašo viršuje ir skambėti"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Rodyti ekrane ir skambėti"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Įprastos spalvos"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nakties spalvos"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Tinkintos spalvos"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Nežinomos spalvos"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Spalvų keitimas"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Rodyti Sparčiųjų nustatymų išklotinės elementą"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Įgalinti tinkintą transformavimą"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Taikyti"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Nustatymų patvirtinimas"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Dėl kai kurių spalvų nustatymų įrenginys gali būti netinkamas naudoti. Spustelėkite „Gerai“, kad patvirtintumėte šiuos spalvų nustatymus. Kitaip šie nustatymai bus nustatyti iš naujo po 10 sekundžių."</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 76bc30f..0143fea 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -302,7 +302,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Meklēt"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nevarēja palaist lietotni <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Vairāk"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Vēsture"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Vēl <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontāls dalījums"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikāls dalījums"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Pielāgots dalījums"</string>
@@ -365,7 +365,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Ieslēgts akumulatora enerģijas taupīšanas režīms"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Samazina veiktspēju un fona datus"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izslēgt akumulatora jaudas taupīšanu"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Saturs paslēpts"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sāks uzņemt visu, kas tiks rādīts jūsu ekrānā."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Vairs nerādīt"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Dzēst visu"</string>
@@ -450,4 +449,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Lietot paziņojumiem “<xliff:g id="TOPIC_NAME">%1$s</xliff:g>”"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Lietot visiem šīs lietotnes paziņojumiem"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloķēts"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Nav svarīgs"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Parasts"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Ļoti svarīgs"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Steidzams"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nekad nerādīt šos paziņojumus"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Rādīt šos paziņojumus bez skaņas signāla"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Rādīt ekrānā ar skaņas signālu"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Parastas krāsas"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nakts krāsas"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Pielāgotas krāsas"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Nezināmas krāsas"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Krāsu pārveidošana"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ātro iestatījumu elementa rādīšana"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Pielāgotās pārveidošanas iespējošana"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Lietot"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Iestatījumu apstiprināšana"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Noteiktu krāsu iestatījumu dēļ šī ierīce var kļūt nelietojama. Lai apstiprinātu šos krāsu iestatījumus, noklikšķiniet uz Labi. Ja to neizdarīsiet, pēc 10 sekundēm šie iestatījumi tiks atiestatīti."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index c4db311..c573139 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -42,7 +42,7 @@
<string name="battery_saver_confirmation_title" msgid="5299585433050361634">"Дали да се вклучи штедачот на батерија?"</string>
<string name="battery_saver_confirmation_ok" msgid="7507968430447930257">"Вклучи"</string>
<string name="battery_saver_start_action" msgid="5576697451677486320">"Вклучете го штедачот на батерија"</string>
- <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подесувања"</string>
+ <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Поставки"</string>
<string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоматско ротирање на екранот"</string>
<string name="status_bar_settings_mute_label" msgid="554682549917429396">"ИСКЛ."</string>
@@ -151,7 +151,7 @@
<string name="accessibility_no_sims" msgid="3957997018324995781">"Нема СИМ-картичка"</string>
<string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Променување на мрежата на операторот."</string>
<string name="accessibility_battery_level" msgid="7451474187113371965">"Батерија <xliff:g id="NUMBER">%d</xliff:g> проценти."</string>
- <string name="accessibility_settings_button" msgid="799583911231893380">"Подесувања на систем."</string>
+ <string name="accessibility_settings_button" msgid="799583911231893380">"Поставки на систем."</string>
<string name="accessibility_notifications_button" msgid="4498000369779421892">"Известувања"</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"Избриши известување."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"ГПС е овозможен."</string>
@@ -260,7 +260,7 @@
<string name="quick_settings_media_device_label" msgid="1302906836372603762">"Медиумски уред"</string>
<string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
<string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Само итни повици"</string>
- <string name="quick_settings_settings_label" msgid="5326556592578065401">"Подесувања"</string>
+ <string name="quick_settings_settings_label" msgid="5326556592578065401">"Поставки"</string>
<string name="quick_settings_time_label" msgid="4635969182239736408">"Време"</string>
<string name="quick_settings_user_label" msgid="5238995632130897840">"Јас"</string>
<string name="quick_settings_user_title" msgid="4467690427642392403">"Корисник"</string>
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"пребарај"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> не може да се вклучи."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Повеќе"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Историја"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Уште <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Раздели хоризонтално"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Раздели вертикално"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Раздели прилагодено"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Штедачот на батерија е вклучен"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ја намалува изведбата и податоците во заднина"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Исклучете го штедачот на батерија"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Содржините се скриени"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ќе започне да презема сѐ што се прикажува на вашиот екран."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Не покажувај повторно"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Исчисти сè"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Вклучи"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Важи за известувањата за <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Важи за сите известувања од оваа апликација"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Голема важност"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Итна важност"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Никогаш не ги прикажувај известувањава"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Тивко прикажувај ги на дното на списокот со известувања"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Тивко прикажувај ги известувањава"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Прикажувај ги на врвот на списокот со известувања и дај звучен сигнал"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Појави се на екранот и дај звучен сигнал"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Нормални бои"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Ноќни бои"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Приспособени бои"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознати бои"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Промена на бојата"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочка Брзи поставки"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Овозможи приспособено трансформирање"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Примени"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потврдете ги поставките"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Некои поставки на боите може да го направат уредот неупотреблив. Кликнете на Во ред за да ги потврдите овие поставки на боите, инаку тие поставки ќе се ресетираат по 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 20ca46e..c6a08e6 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"തിരയുക"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ആരംഭിക്കാനായില്ല."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"കൂടുതൽ"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ചരിത്രം"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> എണ്ണം കൂടി"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"തിരശ്ചീനമായി വേർതിരിക്കുക"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ലംബമായി വേർതിരിക്കുക"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ഇഷ്ടാനുസൃതമായി വേർതിരിക്കുക"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ബാറ്ററി സേവർ ഓണാണ്"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"പ്രവർത്തനവും പശ്ചാത്തല ഡാറ്റയും കുറയ്ക്കുന്നു"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ബാറ്ററി സേവർ ഓഫാക്കുക"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"കോൺടാക്റ്റുകൾ മറച്ചു"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"നിങ്ങളുടെ സ്ക്രീനിൽ പ്രദർശിപ്പിച്ചിരിക്കുന്ന എല്ലാ കാര്യങ്ങളും <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ക്യാപ്ചർ ചെയ്യുന്നത് ആരംഭിക്കും."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"വീണ്ടും കാണിക്കരുത്"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"എല്ലാം മായ്ക്കുക"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ഓണാക്കുക"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> അറിയിപ്പുകളിലേക്ക് പ്രയോഗിക്കുക"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ഈ ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളിലേക്കും പ്രയോഗിക്കുക"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ബ്ലോക്കുചെയ്തു"</string>
+ <string name="low_importance" msgid="4109929986107147930">"താഴ്ന്ന പ്രാധാന്യം"</string>
+ <string name="default_importance" msgid="8192107689995742653">"സാധാരണ പ്രാധാന്യം"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ഉയർന്ന പ്രാധാന്യം"</string>
+ <string name="max_importance" msgid="5089005872719563894">"അടിയന്തര പ്രാധാന്യം"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ഈ അറിയിപ്പുകൾ ഒരിക്കലും കാണിക്കരുത്"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"അറിയിപ്പ് ലിസ്റ്റിന്റെ താഴെ ശബ്ദമുണ്ടാക്കാതെ കാണിക്കുക"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
+ <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"സാധാരണ വര്ണ്ണങ്ങൾ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"രാത്രി വര്ണ്ണങ്ങൾ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ഇഷ്ടാനുസൃത വര്ണ്ണങ്ങൾ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"തിരിച്ചറിയാനാകാത്ത വർണ്ണങ്ങൾ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"വർണ്ണ പരിഷ്കരണം"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ദ്രുത ക്രമീകരണ ടൈൽ കാണിക്കുക"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"ഇഷ്ടാനുസൃത പരിവർത്തനം പ്രവർത്തനക്ഷമമാക്കുക"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ബാധകമാക്കുക"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ക്രമീകരണം സ്ഥിരീകരിക്കുക"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ചില വർണ്ണ ക്രമീകരണത്തിന് ഈ ഉപകരണത്തെ ഉപയോഗരഹിതമാക്കാനാകും. ഈ വർണ്ണ ക്രമീകരണം സ്ഥിരീകരിക്കുന്നതിന് ശരി എന്നതിൽ ക്ലിക്കുചെയ്യുക, അല്ലെങ്കിൽ 10 സെക്കൻഡിന് ശേഷം ഈ ക്രമീകരണം പുനഃക്രമീകരിക്കപ്പെടും."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 1a15870..91c817a 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -299,7 +299,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"хайх"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>-г эхлүүлж чадсангүй."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Илүү"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Түүх"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Илүү"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Хэвтээ чиглэлд хуваах"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Босоо чиглэлд хуваах"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Хүссэн хэлбэрээр хуваах"</string>
@@ -362,7 +362,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Батерей хэмнэгч асаалттай"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Ажиллагаа болон далд датаг бууруулна"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Батерей хэмнэгчийг унтраах"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Контентыг нуусан"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> таны дэлгэц дээр гаргасан бүх зүйлийн зургийг авч эхэлнэ."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Дахиж үл харуулах"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Бүгдийг арилгах"</string>
@@ -447,4 +446,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> мэдэгдэлд хэрэгжүүлэх"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Энэ апп-н бүх мэдэгдэлд хэрэгжүүлэх"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Блоклосон"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Бага ач холбогдолтой"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Энгийн ач холбогдолтой"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Өндөр ач холбогдолтой"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Яаралтай ач холбогдолтой"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Дэлгэцэнд яаралтайгаар дуутай гаргах"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Хэвийн өнгө"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Шөнийн өнгө"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Өгөгдмөл өнгө"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Үл мэдэгдэх өнгө"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Өнгөний өөрчлөлт"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Түргэн тохиргооны хэсгийг харуулах"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Өгөгдмөл өөрчлөлтийг идэвхжүүлэх"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Хэрэгжүүлэх"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Тохиргоог баталгаажуулах"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Зарим өнгөний тохиргоо энэ төхөөрөмжийг ашиглах боломжгүй болгож болзошгүй. OK товчлуурыг дарж эдгээр өнгөний тохиргоог зөвшөөрөхгүй бол энэ тохиргоо нь 10 секундын дараа шинэчлэгдэх болно."</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 4729a04..5d3a96f 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"शोधा"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करणे शक्य झाले नाही."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"अधिक"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"इतिहास"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"आणखी <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"क्षैतिज विभाजित करा"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"अनुलंब विभाजित करा"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"सानुकूल विभाजित करा"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"बॅटरी बचतकर्ता चालू आहे"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"कार्यप्रदर्शन आणि पार्श्वभूमी डेटा कमी करते"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"बॅटरी बचतकर्ता बंद करा"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"लपविलेली सामग्री"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> आपल्या स्क्रीनवर प्रदर्शित होणारी प्रत्येक गोष्ट कॅप्चर करणे प्रारंभ करेल."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"पुन्हा दर्शवू नका"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सर्व साफ करा"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनांवर लागू करा"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"या अॅपमधील सर्व सूचनांवर लागू करा"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</string>
+ <string name="low_importance" msgid="4109929986107147930">"कमी महत्त्व"</string>
+ <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
+ <string name="high_importance" msgid="1527066195614050263">"सर्वाधिक महत्व"</string>
+ <string name="max_importance" msgid="5089005872719563894">"त्वरित महत्त्व"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"या सूचना कधीही दर्शवू नका"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"या सूचना शांतपणे दर्शवा"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
+ <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"रात्रीचे रंग"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"सानुकूल रंग"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रंग"</string>
+ <string name="color_transform" msgid="6985460408079086090">"रंग सुधारणा"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिंग्ज टाइल दर्शवा"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"सानुकूल रूपांतरण सक्षम करा"</string>
+ <string name="color_apply" msgid="9212602012641034283">"लागू करा"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"सेटिंग्जची पुष्टी करा"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"काही रंग सेटिंग्ज या डिव्हाइसला निरुपयोगी करू शकतात. या रंग सेटिंग्जची पुष्टी करण्यासाठी ठीक आहे दाबा अन्यथा या सेटिंग्ज 10 सेकंदांनंतर रीसेट होतील."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 9a0a0c0..f0a013c 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"cari"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Tidak dapat memulakan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Lagi"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Sejarah"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Lagi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Mendatar Terpisah"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Menegak Terpisah"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tersuai Terpisah"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Penjimat bateri dihidupkan"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Mengurangkan prestasi dan data latar belakang"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Matikan penjimat bateri"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Kandungan tersembunyi"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> akan mula mengabadikan semua yang dipaparkan pada skrin anda.."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Jangan tunjukkan lagi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Kosongkan semua"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Gunakan untuk pemberitahuan <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Gunakan untuk semua pemberitahuan daripada apl ini"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Disekat"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Kepentingan biasa"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Kepentingan segera"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan pemberitahuan ini secara senyap"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Intai pada skrin dan bunyikan"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Warna biasa"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Warna tersuai"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Warna tidak diketahui"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Pengubahsuaian warna"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tunjukkan jubin Tetapan Pantas"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Dayakan jelmaan tersuai"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Gunakan"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Sahkan tetapan"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Sesetengah tetapan warna boleh menjadikan peranti ini tidak dapat digunakan. Klik OK untuk mengesahkan tetapan warna ini, jika tidak, tetapan ini akan ditetapkan semula selepas 10 saat."</string>
</resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 3f1b8a7..75008cb 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ရှာဖွေရန်"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ကို မစနိုင်ပါ။"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"နောက်ထပ်"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"မှတ်တမ်း"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"နောက်ထပ် <xliff:g id="NUMBER">%d</xliff:g> ခု"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ဘက်ထရီ ချွေတာသူ ဖွင့်ထား"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"လုပ်ကိုင်မှုကို လျှော့ချလျက် နောက်ခံ ဒေတာကို ကန့်သတ်သည်"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ဘက်ထရီ ချွေတာမှုကို ပိတ်ထားရန်"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"အကြောင်းအရာများ ဝှက်ထား"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> က သင်၏ မျက်နှာပြင် ပေါ်မှာ ပြသထားသည့် အရာတိုင်းကို စတင် ဖမ်းယူမည်။"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"နောက်ထပ် မပြပါနှင့်"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"အားလုံး ရှင်းလင်းရန်"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ဖွင့်ပါ"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"သတိပေးချက် <xliff:g id="TOPIC_NAME">%1$s</xliff:g> ခုသို့သက်ရောက်စေပါ"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ဤအက်ပ်မှ သတိပေးချက်များအားလုံးသို့ သက်ရောက်စေပါ"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ပိတ်ဆို့ထားသည်"</string>
+ <string name="low_importance" msgid="4109929986107147930">"အနည်းငယ်သာ အရေးပါသည်"</string>
+ <string name="default_importance" msgid="8192107689995742653">"သာမန်သာ အရေးပါသည်"</string>
+ <string name="high_importance" msgid="1527066195614050263">"အလွန်အရေးပါသည်"</string>
+ <string name="max_importance" msgid="5089005872719563894">"အရေးတကြီး အရေးပါသည်"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ဤသတိပေးချက်များကို ဘယ်တော့မှမပြပါနှင့်"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"သတိပေးချက်စာရင်း၏ အောက်ဆုံးတွင် တိတ်တဆိတ်ပြပါ"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ဤသတိပေးချက်များကို တိတ်တဆိတ်ပြပါ"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"သတိပေးချက်စာရင်းများ၏ ထိပ်တွင်ပြကာ အသံဖွင့်ပါ"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"မျက်နှာပြင်ပေါ်သို့ ဖော်ပြကာ အသံဖွင့်ပါ"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ပုံမှန် အရောင်များ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ည အရောင်များ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"စိတ်ကြိုက် အရောင်များ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"မသိသည့် အရောင်များ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"အရောင် မွမ်းမံမှု"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"အမြန် ဆက်တင် လေးထောင့်ကွက်ကို ပြပါ"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"စိတ်ကြိုက် ပြောင်းလဲမှုကို ဖွင့်ပါ"</string>
+ <string name="color_apply" msgid="9212602012641034283">"အသုံးပြုပါ"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ဆက်တင်များကို အတည်ပြုပါ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"အချို့သော အရောင်ဆက်တက်များက ဤကိရိယာကို သုံးမရအောင် လုပ်ပစ်နိုင်ပါသည်။ ဤအရောင် ဆက်တင်များကို အတည်ပြုရန် အိုကေကို နှိပ်ပါ၊ သို့မဟုတ် ဤဆက်တင်များကို ၁၀ စက္ကန့် အကြာတွင် ပြန်ညှိလိုက်ပါမည်။"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 8bcf35e..295a49a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"Søk"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kunne ikke starte <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mer"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Logg"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> til"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Del horisontalt"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Del vertikalt"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Del tilpasset"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparing er på"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduserer ytelsen og begrenser bakgrunnsdataene"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Slå av batterisparing"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Innholdet er skjult"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar opp alt som vies på skjermen din."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ikke vis igjen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Fjern alt"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Bruk for varsler for <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Bruk for alle varslene fra denne appen"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokkert"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Lav viktighet"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Vanlig viktighet"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Høy viktighet"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Svært høy viktighet"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldri vis disse varslene"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Vis nederst på varsellisten uten lyd"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse varslene uten lyd"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på varsellisten med lyd"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Vis fort på skjermen med lyd"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normale farger"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nattfarger"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Spesialtilpassede farger"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Ukjente farger"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Fargemodifisering"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Vis ruten for hurtiginnstillinger"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Slå på spesialtilpasset forvandling"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Bruk"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Bekreft innstillingene"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Noen fargeinnstillinger kan gjøre denne enheten ubrukelig. Klikk på OK for å bekrefte disse fargeinnstillingene, ellers blir de tilbakestilt etter ti sekunder."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 49413b3..d0aa510 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"खोजी गर्नुहोस्"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"सुरु गर्न सकिएन <xliff:g id="APP">%s</xliff:g>।"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"थप"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"इतिहास"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> थप"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"तेर्सो रूपमा विभाजन गर्नुहोस्"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ठाडो रूपमा विभाजन गर्नुहोस्"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"अनुकूलन विभाजन गर्नुहोस्"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ब्याट्रि सेभर चालु छ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"प्रदर्शन र पृष्ठभूमि डेटा घटाउँनुहोस्"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ब्याट्री बचत बन्द गर्नुहोस्"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"लुकेका सामाग्रीहरू"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ले आफ्नो स्क्रीनमा प्रदर्शित हुने सबै खिच्न शुरू गर्नेछ।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"फेरि नदेखाउनुहोस्"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"सबै हटाउनुहोस्"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> सूचनाहरूमा लागू गर्नुहोस्"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"यो अनुप्रयोगका सबै सूचनाहरूमा लागू गर्नुहोस्"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"रोकियो"</string>
+ <string name="low_importance" msgid="4109929986107147930">"न्यून महत्त्व"</string>
+ <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
+ <string name="high_importance" msgid="1527066195614050263">"उच्च महत्त्व"</string>
+ <string name="max_importance" msgid="5089005872719563894">"जरूरी महत्त्व"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"यी सूचनाहरू कहिल्यै नदेखाउनुहोस्"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"सूचीको फेदमा बिना आवाज देखाउनुहोस्"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"यी सूचनाहरू बिना आवाज देखाउनुहोस्"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रिनमा हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
+ <string name="notification_done" msgid="5279426047273930175">"सम्पन्न भयो"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रङहरू"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"रात्री रङहरू"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"अनुकूलन रङहरू"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"अज्ञात रङहरू"</string>
+ <string name="color_transform" msgid="6985460408079086090">"रङ परिमार्जन"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"द्रुत सेटिङ टाइल देखाउनुहोस्"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"अनुकूलन रूपान्तरण सक्रिय गर्नुहोस्"</string>
+ <string name="color_apply" msgid="9212602012641034283">"लागू गर्नुहोस्"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"सेटिङहरूको पुष्टि गर्नुहोस्"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"केही रङ सेटिङहरूले यस यन्त्रलाई अनुपयोगी बनाउन सक्छन्। यी रङ सेटिङहरू पुष्टि गर्न ठीक छ मा क्लिक गर्नुहोस्, अन्यथा यी सेटिङहरू १० सेकेण्डपछि रिसेट हुनेछन्।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7ded71c..75812ad 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"zoeken"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Kan <xliff:g id="APP">%s</xliff:g> niet starten."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Meer"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Geschiedenis"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Nog <xliff:g id="NUMBER">%d</xliff:g> andere"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Horizontaal splitsen"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Verticaal splitsen"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Aangepast splitsen"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Accubesparing is ingeschakeld"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Vermindert de prestaties en achtergrondgegevens"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Accubesparing uitschakelen"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> gaat alles vastleggen dat wordt weergegeven op je scherm."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Niet opnieuw weergeven"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Alles wissen"</string>
@@ -406,7 +405,7 @@
<string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Verbergen"</string>
<string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> wil het volumedialoogvenster zijn."</string>
<string name="volumeui_prompt_allow" msgid="7954396902482228786">"Toestaan"</string>
- <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
+ <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weigeren"</string>
<string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
<string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
<string name="group_summary_concadenation" msgid="6846402378100148789">", "</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Inschakelen"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Toepassen op meldingen voor <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Toepassen op alle meldingen van deze app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Geblokkeerd"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Klein belang"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normaal belang"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgent belang"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Deze meldingen nooit weergeven"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Onder aan de lijst met meldingen weergeven zonder geluid"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Deze meldingen zonder geluid weergeven"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Op het scherm weergeven en geluid laten horen"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleuren"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nachtkleuren"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Aangepaste kleuren"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Onbekende kleuren"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Kleuraanpassing"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tegel voor \'Snelle instellingen\' weergeven"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Aangepast transformeren inschakelen"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Toepassen"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Instellingen bevestigen"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Bij sommige kleurinstellingen kan het apparaat onbruikbaar worden. Klik op OK om deze kleurinstellingen te bevestigen, anders worden deze instellingen na tien seconden gereset."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 3a6fa0f..fc5a3ea 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ਖੋਜੋ"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ਨੂੰ ਚਾਲੂ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"ਹੋਰ"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ਇਤਿਹਾਸ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ਹੋਰ"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ਹੌਰੀਜ਼ੌਂਟਲ ਸਪਲਿਟ"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ਵਰਟੀਕਲ ਸਪਲਿਟ"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"ਕਸਟਮ ਸਪਲਿਟ"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"ਬੈਟਰੀ ਸੇਵਰ ਚਾਲੂ ਹੈ"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ਪ੍ਰਦਰਸ਼ਨ ਅਤੇ ਪਿਛੋਕੜ ਡਾਟਾ ਘੱਟ ਕਰਦਾ ਹੈ"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ਬੈਟਰੀ ਸੇਵਰ ਬੰਦ ਕਰੋ"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"ਸਮੱਗਰੀਆਂ ਲੁਕਾਈਆਂ ਗਈਆਂ"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਉਹ ਸਭ ਕੁਝ ਕੈਪਚਰ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰ ਦੇਵੇਗਾ, ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ ਤੇ ਡਿਸਪਲੇ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ਸਾਰੇ ਹਟਾਓ"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ਚਾਲੂ ਕਰੋ"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ਇਸ ਐਪ ਦੀਆਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ \'ਤੇ ਲਾਗੂ ਕਰੋ"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"ਬਲੌਕ ਕੀਤਾ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"ਘੱਟ ਮਹੱਤਤਾ"</string>
+ <string name="default_importance" msgid="8192107689995742653">"ਸਧਾਰਨ ਮਹੱਤਤਾ"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ਵੱਧ ਮਹੱਤਤਾ"</string>
+ <string name="max_importance" msgid="5089005872719563894">"ਜ਼ਰੂਰੀ ਮਹੱਤਤਾ"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਕਦੇ ਨਾ ਵਿਖਾਓ"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"ਸਧਾਰਨ ਰੰਗ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"ਰਾਤ ਦੇ ਰੰਗ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"ਕਸਟਮ ਰੰਗ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"ਅਗਿਆਤ ਰੰਗ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"ਰੰਗ ਸੋਧ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲ ਵਿਖਾਓ"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"ਕਸਟਮ ਤਬਦੀਲੀ ਯੋਗ ਬਣਾਓ"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ਲਾਗੂ ਕਰੋ"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"ਕੁਝ ਰੰਗ ਸੈਟਿੰਗਾਂ ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬੇਕਾਰ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇਹਨਾਂ ਰੰਗ ਸੈਟਿੰਗਾਂ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ ਠੀਕ \'ਤੇ ਕਲਿੱਕ ਕਰੋ, ਨਹੀਂ ਤਾਂ ਇਹ ਸੈਟਿੰਗਾਂ 10 ਸਕਿੰਟ ਬਾਅਦ ਮੁੜ-ਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ।"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 42c8f6e..8ef50c9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"szukaj"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Nie udało się uruchomić aplikacji <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Więcej"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historia"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"i jeszcze <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podziel poziomo"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podziel pionowo"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Podziel niestandardowo"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Oszczędzanie baterii jest włączone"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Zmniejsza wydajność i ogranicza dane w tle"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Wyłącz oszczędzanie baterii"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Treści ukryte"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> będzie zapisywać wszystko, co wyświetli się na ekranie."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nie pokazuj ponownie"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Usuń wszystkie"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Zastosuj do powiadomień typu <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Zastosuj do wszystkich powiadomień z tej aplikacji"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Ważne"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Bardzo ważne"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Pilne"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nigdy nie pokazuj tych powiadomień"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Pokazuj na dole listy powiadomień bez sygnału dźwiękowego"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Pokazuj na górze listy powiadomień i sygnalizuj dźwiękiem"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Kolory standardowe"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Kolory nocne"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Kolory niestandardowe"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Nieznane kolory"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Zmiana koloru"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pokazuj kafelek szybkich ustawień"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Włącz przekształcenie niestandardowe"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Zastosuj"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potwierdź ustawienia"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Niektóre ustawienia kolorów mogą utrudniać korzystanie z urządzenia. Kliknij OK, by potwierdzić te ustawienia kolorów. Jeśli tego nie zrobisz, zostaną one zresetowane po 10 sekundach."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e009cea..8f61478 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Histórico"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 47949e0..8a727a1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar o <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Histórico"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"A poupança de bateria está ligada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados de segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a poupança de bateria"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"O(a) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> vai começar a captar tudo o que é apresentado no ecrã."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar de novo"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -426,7 +425,7 @@
<string name="status_bar_airplane" msgid="7057575501472249002">"Modo de avião"</string>
<string name="add_tile" msgid="2995389510240786221">"Adicionar mosaico"</string>
<string name="broadcast_tile" msgid="3894036511763289383">"Mosaico de transmissão"</string>
- <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g> se desativar esta funcionalidade antes dessa hora"</string>
+ <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme (<xliff:g id="WHEN">%1$s</xliff:g>) se desativar esta funcionalidade antes dessa hora"</string>
<string name="zen_alarm_warning" msgid="444533119582244293">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="3980063409350522735">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="4242179982586714810">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações desta aplicação"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importância alta"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar estas notificações"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações sem som"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificações sem som"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar no ecrã e emitir som"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar o mosaico de Definições rápidas"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar as definições"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algumas definições de cor podem tornar este dispositivo instável. Clique em OK para confirmar estas definições de cor. Caso contrário, estas definições serão repostas após 10 segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e009cea..8f61478 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"pesquisar"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Não foi possível iniciar <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mais"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Histórico"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Mais <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divisão horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divisão vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divisão personalizada"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"A Economia de bateria está ativada"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduz o desempenho e os dados em segundo plano"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Desativar a economia de bateria"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Conteúdo oculto"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> começará a capturar tudo o que for exibido na tela."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Não mostrar novamente"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Limpar tudo"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicar a notificações de <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicar a todas as notificações deste app"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Cores desconhecidas"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificação de cor"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Mostrar bloco de configurações rápidas"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Ativar transformação personalizada"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 03b9556..3ab8bf2 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -302,7 +302,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mai mult"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Istoric"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Încă <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Divizare pe orizontală"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Divizare pe verticală"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Divizare personalizată"</string>
@@ -365,7 +365,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Economisirea bateriei este activată"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Reduce performanța și datele de fundal"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Dezactivați economisirea bateriei"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Conținutul este ascuns"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va începe să captureze tot ceea ce se afișează pe ecran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nu se mai afișează"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Ștergeți toate notificările"</string>
@@ -450,4 +449,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Aplicați notificărilor de tip <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Aplicați tuturor notificărilor de la această aplicație"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blocate"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Importanță redusă"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Importanță normală"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Importanță ridicată"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Importanță: urgente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Aceste notificări nu se afișează niciodată"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Aceste notificări se afișează fără a se emite un sunet"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Culori normale"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Culori de noapte"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Culori personalizate"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Culori necunoscute"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modificarea culorilor"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Afișați caseta cu Setările rapide"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Activați transformarea personalizată"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Aplicați"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Confirmați setările"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Unele setări pentru culori pot face dispozitivul să nu mai funcționeze. Dați clic pe OK pentru a confirma aceste setări pentru culori. În caz contrar, acestea se vor reseta după 10 secunde."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a196ed6..6ffd333 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"поиск"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не удалось запустить приложение \"<xliff:g id="APP">%s</xliff:g>\""</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Ещё"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Журнал"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Ещё <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Разделить по горизонтали"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Разделить по вертикали"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Разделить по-другому"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Включен режим энергосбережения"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Откл. фоновой передачи данных"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Отключить режим энергосбережения"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Содержимое скрыто"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Приложение <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> получит доступ к изображению на экране устройства."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Больше не показывать"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Очистить все"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Применить к уведомлениям на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Применить ко всем уведомлениям этого приложения"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Блокировка"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Низкая важность"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Средняя важность"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Высокая важность"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Крайняя важность"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Не показывать эти уведомления."</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Показывать без звука в конце списка уведомлений."</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Показывать уведомления без звука."</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Показывать со звуком в начале списка уведомлений."</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Показывать со звуком поверх всех окон."</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Обычные цвета"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Ночные цвета"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Собственные цвета"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Неизвестные цвета"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Цветовые настройки"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показывать панель быстрых настроек"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Включить собственные настройки"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Применить"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Подтвердите настройки"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Некоторые цветовые настройки могут затруднить работу с устройством. Чтобы применить выбранные параметры, нажмите \"ОК\". В противном случае они будут сброшены через 10 секунд."</string>
</resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 297ef78..efbc042 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"සෙවීම"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> ආරම්භ කළ නොහැක."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"තවත්"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ඉතිහාසය"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"තව <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"තිරස්ව වෙන් කරන්න"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"සිරස්ව වෙන් කරන්න"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"අභිමත ලෙස වෙන් කරන්න"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"බැටරිය සුරකින්නා සක්රීයයි"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ක්රියාකාරිත්වය සහ පසුබිම් දත්ත අඩු කරන්න"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"බැටරි සුරැකීම අක්රිය කරන්න"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"සැඟවුණු සම්බන්ධතා"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"ඔබගේ තීරයේ දර්ශනය වන සෑම දෙයම <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ලබාගැනීම ආරම්භ කරන ලදි."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"නැවත නොපෙන්වන්න"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"සියල්ල හිස් කරන්න"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්රියාත්මක කරන්නද?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්රියාත්මක කළ යුතුය."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ක්රියාත්මක කරන්න"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> දැනුම්දීම් වෙත යොදන්න"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"මෙම යෙදුම වෙතින් වන සියලු දැනුම්දීම් සඳහා යොදන්න"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"අවහිර කරන ලදි"</string>
+ <string name="low_importance" msgid="4109929986107147930">"අඩු වැදගත්කම"</string>
+ <string name="default_importance" msgid="8192107689995742653">"සාමාන්ය වැදගත්කම"</string>
+ <string name="high_importance" msgid="1527066195614050263">"වැඩි වැදගත්කම"</string>
+ <string name="max_importance" msgid="5089005872719563894">"හදිසි වැදගත්කම"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"මෙම දැනුම්දීම් කිසිදා නොපෙන්වන්න"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"දැනුම්දීම් ලැයිස්තුවෙහි පහළින්ම නිශ්ශබ්දව පෙන්වන්න"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"තිරයට පැමිණ ශබ්ද කරන්න"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
+ <string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"සාමාන්ය වර්ණ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"රාත්රී වර්ණ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"අභිරුචි වර්ණ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"නොදන්නා වර්ණ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"වර්ණ වෙනස් කිරීම"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"ඉක්මන් සැකසීම් ටයිලය පෙන්වන්න"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"අභිරුචි පරිවර්තනය සබල කරන්න"</string>
+ <string name="color_apply" msgid="9212602012641034283">"යොදන්න"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"සැකසීම් තහවුරු කරන්න"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"සමහර වර්ණ සැකසීම් මෙම උපාංගය භාවිත කළ නොහැකි තත්ත්වයට පත් කළ හැකිය. මෙම වර්ණ සැකසීම් තහවුරු කිරීමට හරි ක්ලික් කරන්න, නැතහොත් මෙම සැකසීම් තත්පර 10කට පසුව යළි සකසනු ඇත."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 8c77eaf..31985b4 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"hľadať"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikáciu <xliff:g id="APP">%s</xliff:g> sa nepodarilo spustiť"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Viac"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"História"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Ďalšie (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Rozdeliť vodorovné"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Rozdeliť zvislé"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Rozdeliť vlastné"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Šetrič batérie je zapnutý"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Obmedzí výkonnosť a prenos údajov na pozadí"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vypnúť šetrič batérie"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Skrytý obsah"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> začne zaznamenávať všetok obsah zobrazený na vašej obrazovke."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Nabudúce nezobrazovať"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Vymazať všetko"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Použiť na upozornenia týkajúce sa témy <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Použiť na všetky upozornenia z tejto aplikácie"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Zablokované"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Nízka dôležitosť"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Normálna dôležitosť"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Vysoká dôležitosť"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Neodkladná dôležitosť"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Tieto upozornenia nikdy nezobrazovať"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Zobrazovať cez obrazovku so zvukovým signálom"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normálne farby"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nočné farby"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastné farby"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznáme farby"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Úprava farieb"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Zobraziť dlaždicu Rýchle nastavenia"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Povoliť vlastnú transformáciu"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Použiť"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potvrdenie nastavení"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Niektoré nastavenia farieb môžu toto zariadenie znefunkčniť. Tieto nastavenia farieb potvrdíte kliknutím na tlačidlo OK, ináč sa tieto nastavenia o 10 sekúnd obnovia."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 9578dee..7c8d443 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"iskanje"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Aplikacije <xliff:g id="APP">%s</xliff:g> ni bilo mogoče zagnati."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Več"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Zgodovina"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"In še <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Razdeli vodoravno"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Razdeli navpično"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Razdeli po meri"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Varčevanje z energijo akumulatorja je vklopljeno"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Omeji zmogljivost delovanja in prenos podatkov v ozadju"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Izklop varčevanja z energijo akumulatorja"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Vsebina je skrita"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> bo začela zajemati vse, kar je prikazano na zaslonu."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Tega ne prikaži več"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Izbriši vse"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vklop"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Uporabi za obvestila za temo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Uporabi za vsa obvestila za to aplikacijo"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Nizka pomembnost"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Običajna pomembnost"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Visoka pomembnost"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Nujna pomembnost"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikoli ne prikaži teh obvestil"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Prikaži na dnu seznama obvestil brez zvoka"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži ta obvestila brez zvoka"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Običajne barve"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nočne barve"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Barve po meri"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Neznane barve"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Spreminjanje barv"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Prikaz ploščice s hitrimi nastavitvami"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Omogočanje spremembe po meri"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Uporabi"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Potrditev nastavitev"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Zaradi nekaterih barvnih nastavitev lahko postane ta naprava neuporabna. Kliknite »V redu«, če želite potrditi te barvne nastavitve. V nasprotnem primeru se bodo čez 10 sekund ponastavile na prvotno vrednost."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 8b19bd8..c8add94 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"kërko"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nuk mundi të nisej."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Më shumë"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historiku"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> të tjera"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Ndaje horizontalisht"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Ndaj vertikalisht"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ndaj të personalizuarën"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kursimi i baterisë është i aktivizuar"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Pakëson veprimtarinë dhe të dhënat në sfond"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Çaktivizo kursimin e baterisë"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Përmbajtjet janë të fshehura"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> do të fillojë të regjistrojë çdo gjë që shfaqet në ekran."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Mos e shfaq sërish"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Pastroji të gjitha"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivizo"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Zbatoje për njoftimet nga <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Zbatoje për të gjitha njoftimet nga ky aplikacion"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"I bllokuar"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Rëndësi e ulët"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Rëndësi normale"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Rëndësi e lartë"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Rëndësi urgjente"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Mos i shfaq asnjëherë këto njoftime"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Shfaqi në heshtje në fund të listës së njoftimeve"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Shfaqi këto njoftime në heshtje"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
+ <string name="notification_done" msgid="5279426047273930175">"U krye"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Ngjyrat normale"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Ngjyrat e natës"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Ngjyrat e personalizuara"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Ngjyra të panjohura"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Modifikimi i ngjyrës"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Pllakëza Shfaq cilësimet e shpejta"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Zbato transformimin e personalizuar"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Zbato"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Konfirmo cilësimet"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Disa cilësime ngjyrash mund ta bëjnë këtë pajisje të papërdorshme. Kliko OK për të konfirmuar këto cilësime ngjyrash, përndryshe këto cilësime do të rivendosen pas 10 sekondash."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f22fa4e..bec1fd4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -302,7 +302,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"претражи"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Покретање апликације <xliff:g id="APP">%s</xliff:g> није успело."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Још"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Историја"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Још <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Подели хоризонтално"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Подели вертикално"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Прилагођено дељење"</string>
@@ -365,7 +365,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Штедња батерије је укључена"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Смањује перформансе и позадинске податке"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Искључи штедњу батерије"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Садржај је сакривен"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ће почети да снима све што се приказује на екрану."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Не приказуј поново"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Обриши све"</string>
@@ -450,4 +449,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Примени на обавештења о теми <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Примени на сва обавештења из ове апликације"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Блокирана"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Приказују се у дну листе обавештења без звука"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Ова обавештења се приказују без звука"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Приказују се у врху листе обавештења и емитује се звук"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Накратко се приказују на екрану и емитује се звук"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Нормалне боје"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Ноћне боје"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Прилагођене боје"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Непознате боје"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Измена боја"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Прикажи плочицу Брза подешавања"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Омогући прилагођену трансформацију"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Примени"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Потврдите подешавања"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Нека подешавања боја могу да учине уређај неупотребљивим. Кликните на Потврди да бисте потврдили ова подешавања боја, пошто ће се у супротном ова подешавања ресетовати након 10 секунди."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 269881a..d4a9cdc 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"sök"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Det gick inte att starta appen <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Mer"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historik"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> till"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Batterisparläget har aktiverats"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Minskar prestanda och bakgrundsdata"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Inaktivera batterisparläget"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Innehåll har dolts"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tar en bild av allt som visas på skärmen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Visa inte igen"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Rensa alla"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Ändra för alla aviseringar för <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Ändra för alla aviseringar från den här appen"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Blockerad"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Oviktig avisering"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Vanlig avisering"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Viktig avisering"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Brådskande avisering"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Visa aldrig de här aviseringarna"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Visa längst ned på listan, utan ljud"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Visa aviseringarna utan ljud"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Visa högst upp på listan, med ljud"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Visa på skärmen, med ljud"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normala färger"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Nattfärger"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Anpassade färger"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Okända färger"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Färgändring"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Visa rutan Snabbinställningar"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Aktivera anpassad omvandling"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Verkställ"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Bekräfta inställningarna"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Vissa färginställningar kan göra den här enheten oanvändbar. Klicka på OK om du vill bekräfta färginställningarna, annars återställs inställningarna efter 10 sekunder."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 2696242..2ffbf2b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"tafuta"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Haikuweza kuanzisha <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Zaidi"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Historia"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Nyingine <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gawanya Mlalo"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Gawanya Wima"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Maalum Iliyogawanywa"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Kiokoa betri kimewashwa"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Hupunguza utendaji na data ya chini chini"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Zima kiokoa betri"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Maudhui yamefichwa"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> itaanza kupiga picha kila kitu kinachoonyeshwa kwenye skrini yako."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Usionyeshe tena"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Futa zote"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Washa"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Tumia katika arifa za <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Tumia katika arifa zote kutoka programu hii"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Amezuiwa"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Umuhimu kiwango cha chini"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Umuhimu wa kiwango cha kawaida"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Umuhimu wa kiwango cha juu"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Umuhimu wa hali ya dharura"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Usionyeshe arifa hizi kamwe"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Onyesha katika sehemu ya chini ya orodha ya arifa bila sauti"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Onyesha arifa hizi bila sauti"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Rangi za kawaida"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Rangi za usiku"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Rangi maalum"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Rangi zisizojulikana"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Ubadilishaji wa rangi"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Onyesha kigae cha Mipangilio ya Haraka"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Washa ubadilishaji maalum"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Tumia"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Thibitisha mipangilio"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Baadhi ya mipangilio ya rangi inaweza kufanya kifaa hiki kisitumike. Bofya Sawa ili uthibitishe mipangilio hii ya rangi, vinginevyo, mipangilio hii itajiweka upya baada ya sekunde 10."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index aa7266e..168a11b 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"தேடு"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ஐத் தொடங்க முடியவில்லை."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"மேலும்"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"வரலாறு"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"மேலும் <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"தனிவிருப்பத்தில் பிரி"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"பேட்டரி சேமிப்பான் இயக்கத்தில் உள்ளது"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"செயல்திறனையும் பின்புலத் தரவையும் குறைக்கிறது"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"பேட்டரி சேமிப்பானை முடக்கு"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"மறைந்துள்ள உள்ளடக்கம்"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"திரையில் காட்டப்படும் அனைத்தையும் <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> படமெடுக்கும்."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"மீண்டும் காட்டாதே"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"எல்லாவற்றையும் அழி"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"இயக்கு"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> அறிவிப்புகளுக்குப் பயன்படுத்து"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"இந்தப் பயன்பாட்டிலிருந்து வரும் எல்லா அறிவிப்புகளுக்கும் பயன்படுத்து"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"தடுக்கப்பட்டது"</string>
+ <string name="low_importance" msgid="4109929986107147930">"முக்கியத்துவம் (குறைவு)"</string>
+ <string name="default_importance" msgid="8192107689995742653">"முக்கியத்துவம் (இயல்பு)"</string>
+ <string name="high_importance" msgid="1527066195614050263">"முக்கியத்துவம் (அதிகம்)"</string>
+ <string name="max_importance" msgid="5089005872719563894">"முக்கியத்துவம் (அவசரம்)"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"இந்த அறிவிப்புகளை ஒருபோதும் காட்டாதே"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"ஒலியின்றி அறிவிப்புப் பட்டியலின் கீழே காட்டு"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டு"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"ஒலியுடன் திரையில் காட்டு"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
+ <string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"இயல்பான வண்ணங்கள்"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"இரவுநேர வண்ணங்கள்"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"தனிப்பயன் வண்ணங்கள்"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"அறியப்படாத வண்ணங்கள்"</string>
+ <string name="color_transform" msgid="6985460408079086090">"வண்ண மாற்றம்"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"விரைவு அமைப்புகள் டைலைக் காட்டு"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"தனிப்பயன் வண்ண மாற்றத்தை இயக்கு"</string>
+ <string name="color_apply" msgid="9212602012641034283">"பயன்படுத்து"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"அமைப்புகளை உறுதிப்படுத்து"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"சில வண்ண அமைப்புகள் இந்தச் சாதனத்தைப் பயன்படுத்த முடியாதபடி செய்யலாம். இந்த வண்ண அமைப்புகளை உறுதிப்படுத்த, சரி என்பதைக் கிளிக் செய்யவும், இல்லையெனில் இந்த அமைப்புகள் 10 வினாடிகளுக்குப் பின் மீட்டமைக்கப்படும்."</string>
</resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 06b7ccf3..086dede 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"శోధించు"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g>ని ప్రారంభించడం సాధ్యపడలేదు."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"మరింత"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"చరిత్ర"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"మరో <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"సమతలంగా విభజించు"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"లంబంగా విభజించు"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"అనుకూలంగా విభజించు"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"బ్యాటర్ సేవర్ ఆన్ చేయబడింది"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"పనితీరుని మరియు నేపథ్య డేటాను తగ్గిస్తుంది"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"బ్యాటరీ సేవర్ను ఆఫ్ చేయి"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"కంటెంట్లు దాచబడ్డాయి"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> మీ స్క్రీన్పై కనిపించే ప్రతిదాన్ని క్యాప్చర్ చేయడం ప్రారంభిస్తుంది."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"మళ్లీ చూపవద్దు"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"అన్నీ క్లియర్ చేయండి"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్ను మీ టాబ్లెట్తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ఆన్ చేయి"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> నోటిఫికేషన్లకు వర్తింపజేయి"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"ఈ అనువర్తనం నుండి అందించబడే అన్ని నోటిఫికేషన్లకు వర్తింపజేయి"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"బ్లాక్ చేయబడింది"</string>
+ <string name="low_importance" msgid="4109929986107147930">"తక్కువ ప్రాముఖ్యత"</string>
+ <string name="default_importance" msgid="8192107689995742653">"సాధారణ ప్రాముఖ్యత"</string>
+ <string name="high_importance" msgid="1527066195614050263">"అధిక ప్రాముఖ్యత"</string>
+ <string name="max_importance" msgid="5089005872719563894">"అత్యవసర ప్రాముఖ్యత"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ఈ నోటిఫికేషన్లను ఎప్పుడూ చూపదు"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"నోటిఫికేషన్ల జాబితా దిగువ భాగంలో శబ్దం లేకుండా చూపుతుంది"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"ఈ నోటిఫికేషన్లను శబ్దం లేకుండా చూపుతుంది"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"నోటిఫికేషన్ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"స్క్రీన్పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్లు"</string>
+ <string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"సాధారణ రంగులు"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"రాత్రి రంగులు"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"అనుకూల రంగులు"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"తెలియని రంగులు"</string>
+ <string name="color_transform" msgid="6985460408079086090">"రంగు సవరణ"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"శీఘ్ర సెట్టింగ్ల టైల్ను చూపండి"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"అనుకూల పరివర్తనను ప్రారంభించండి"</string>
+ <string name="color_apply" msgid="9212602012641034283">"వర్తింపజేయి"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"సెట్టింగ్లను నిర్ధారించండి"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"కొన్ని రంగు సెట్టింగ్ల వలన ఈ పరికరం ఉపయోగించలేని విధంగా అయిపోవచ్చు. ఈ రంగు సెట్టింగ్లను నిర్ధారించడానికి సరే క్లిక్ చేయండి లేదంటే ఈ సెట్టింగ్లు 10 సెకన్ల తర్వాత రీసెట్ చేయబడతాయి."</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index eb4eb27..8c1a7d3 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ค้นหา"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"ไม่สามารถเริ่มใช้ <xliff:g id="APP">%s</xliff:g>"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"เพิ่มเติม"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"ประวัติ"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"อีก <xliff:g id="NUMBER">%d</xliff:g> งาน"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"แยกในแนวนอน"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"แยกในแนวตั้ง"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"แยกแบบกำหนดเอง"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"เปิดโหมดประหยัดแบตเตอรี่อยู่"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"ลดการใช้แบตเตอรี่และข้อมูลแบ็กกราวด์"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"ปิดโหมดประหยัดแบตเตอรี่"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"เนื้อหาถูกซ่อนไว้"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> จะเริ่มจับภาพทุกอย่างที่แสดงบนหน้าจอ"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"ไม่ต้องแสดงข้อความนี้อีก"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"ล้างทั้งหมด"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"นำไปใช้กับการแจ้งเตือน <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"นำไปใช้กับการแจ้งเตือนทั้งหมดจากแอปนี้"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</string>
+ <string name="low_importance" msgid="4109929986107147930">"ความสำคัญต่ำ"</string>
+ <string name="default_importance" msgid="8192107689995742653">"ความสำคัญปกติ"</string>
+ <string name="high_importance" msgid="1527066195614050263">"ความสำคัญสูง"</string>
+ <string name="max_importance" msgid="5089005872719563894">"ความสำคัญเร่งด่วน"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"ไม่ต้องแสดงการแจ้งเตือนเหล่านี้"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
+ <string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"สีปกติ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"สียามค่ำคืน"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"สีที่กำหนดเอง"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"สีที่ไม่รู้จัก"</string>
+ <string name="color_transform" msgid="6985460408079086090">"การปรับเปลี่ยนสี"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"แสดงไทล์การตั้งค่าด่วน"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"เปิดใช้การเปลี่ยนที่กำหนดเอง"</string>
+ <string name="color_apply" msgid="9212602012641034283">"ใช้"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ยืนยันการตั้งค่า"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"การตั้งค่าสีบางอย่างอาจทำให้อุปกรณ์นี้ใช้งานไม่ได้ คลิกตกลงเพื่อยืนยันการตั้งค่าสีเหล่านี้ มิฉะนั้นระบบจะรีเซ็ตการตั้งค่าหลังจาก 10 วินาที"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a04d66b..4bee3ea 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"maghanap"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Hindi masimulan <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Higit pa"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"History"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Pa"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Split Horizontal"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Split Vertical"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Split Custom"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Naka-on ang tagatipid ng baterya"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Binabawasan ang pagganap at data sa background"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"I-off ang pagtitipid ng baterya"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Nakatago ang mga content"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"Sisimulan ng i-capture ng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ang lahat ng ipinapakita sa iyong screen."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Huwag ipakitang muli"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"I-clear lahat"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Naaangkop sa mga notification tungkol sa <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Naaangkop sa lahat ng notification mula sa app na ito"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Na-block"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Hindi masyadong mahalaga"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Mahalaga"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Napakahalaga"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Mahalagang-mahalaga"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Huwag kailanman ipakita ang mga notification na ito"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Tahimik na ipakita ang mga notification na ito"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Ipakita sa itaas ng listahan ng mga notification at mag-play ng tunog"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Ipasilip sa screen at mag-play ng tunog"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Mga karaniwang kulay"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Madidilim na kulay"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Mga custom na kulay"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Mga hindi kilalang kulay"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Pagbago sa kulay"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Ipakita ang tile ng Mga Mabilisang Setting"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"I-enable ang custom na pagpalit"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Ilapat"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Kumpirmahin ang mga setting"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Maaaring hindi magamit ang device na ito dahil sa ilang setting ng kulay. I-click ang OK upang kumpirmahin ang mga setting ng kulay na ito, kung hindi ay mare-reset ang mga setting na ito pagkatapos ng 10 segundo."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c549798..c0ecc78 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"ara"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> başlatılamadı."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Diğer"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Geçmiş"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Tane Daha"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Yatay Ayırma"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dikey Ayırma"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Özel Ayırma"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Pil tasarrufu açık"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Performansı ve arka plan verilerini azaltır"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Pil tasarrufunu kapat"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"İçerik gizlendi"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>, ekranınızda görüntülenen her şeyi kaydetmeye başlayacak."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Bir daha gösterme"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Tümü temizle"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> bildirimlerine uygula"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Bu uygulamadan gelen tüm bildirimlere uygulansın mı?"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Engellendi"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Önem düzeyi düşük"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Önem düzeyi normal"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Önem düzeyi yüksek"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Önem düzeyi acil"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirimleri hiçbir zaman gösterme"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Bildirim listesinin en altında sessizce göster"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirimleri sessizce göster"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Bildirim listesinin en üstünde göster ve ses çıkar"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Ekrana getir ve ses çıkar"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Normal renkler"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Gece renkleri"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Özel renkler"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Bilinmeyen renkler"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Renk değişikliği"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hızlı Ayarlar kutusunu göster"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Özel dönüşümü etkinleştir"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Uygula"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Ayarları onaylayın"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Bazı renkler bu cihazı kullanılmaz yapabilir. Bu renkleri onaylamak için Tamam\'ı tıklayın. Tıklamazsanız bu ayarlar 10 saniye sonra sıfırlanacaktır."</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index a58c13c..3109403 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -303,7 +303,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"пошук"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Не вдалося запустити <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Більше"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Історія"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"Ще <xliff:g id="NUMBER">%d</xliff:g>"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Розділити горизонтально"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Розділити вертикально"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Розділити (власний варіант)"</string>
@@ -366,7 +366,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Режим заощадження заряду акумулятора ввімкнено"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Знижується продуктивність і обмежуються фонові дані"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Вимкнути режим заощадження заряду акумулятора"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Вміст сховано"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> отримає доступ до всіх даних, які відображаються на вашому екрані."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Більше не показувати"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Очистити все"</string>
@@ -451,4 +450,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Застосувати до сповіщень на тему \"<xliff:g id="TOPIC_NAME">%1$s</xliff:g>\""</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Застосувати до всіх сповіщень із цього додатка"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Заблоковано"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Низький пріоритет"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Стандартний пріоритет"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Високий пріоритет"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Терміново"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколи не показувати ці сповіщення"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Показувати сповіщення внизу списку без звукового сигналу"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Показувати ці сповіщення без звукового сигналу"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Показувати сповіщення вгорі списку зі звуковим сигналом"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Стандартні кольори"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Нічні кольори"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Користувацькі кольори"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Невідомі кольори"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Змінення кольорів"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Показати опцію швидких налаштувань"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Увімкнути користувацьке перетворення"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Застосувати"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Підтвердити налаштування"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Деякі налаштування кольорів можуть зробити цей пристрій непридатним для використання. Натисніть OK, щоб підтвердити налаштування, інакше їх буде скинуто через 10 секунд."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 9e3a6b5..52aa580 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"تلاش کریں"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> کو شروع نہیں کیا جا سکا۔"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"مزید"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"سرگزشت"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> مزید"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"بلحاظ افقی الگ کریں"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"بلحاظ عمودی الگ کریں"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"بلحاظ حسب ضرورت الگ کریں"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"بیٹری سیور آن ہے"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"کارکردگی اور پس منظر کا ڈیٹا کم کر دیتا ہے"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"بیٹری کی بچت آف کریں"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"مواد مخفی ہیں"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> آپ کی اسکرین پر ڈسپلے ہونے والی ہر چیز کو کیپچر کرنا شروع کر دیگی۔"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"دوبارہ نہ دکھائیں"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"سبھی کو صاف کریں"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"<xliff:g id="TOPIC_NAME">%1$s</xliff:g> اطلاعات پر لاگو کریں"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"اس ایپ سے تمام اطلاعات پر لاگو کریں"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</string>
+ <string name="low_importance" msgid="4109929986107147930">"کم اہمیت"</string>
+ <string name="default_importance" msgid="8192107689995742653">"عمومی اہمیت"</string>
+ <string name="high_importance" msgid="1527066195614050263">"زیادہ اہمیت"</string>
+ <string name="max_importance" msgid="5089005872719563894">"فوری اہمیت"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"یہ اطلاعات کبھی مت دکھائیں"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"خاموشی سے یہ اطلاعات دکھائیں"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"اسکرین پر دکھائیں اور آواز چلائیں"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
+ <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"عام رنگ"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"رات کے رنگ"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"حسب ضرورت رنگ"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"نامعلوم رنگ"</string>
+ <string name="color_transform" msgid="6985460408079086090">"رنگوں کی تبدیلی"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"فوری ترتیبات والی ٹائل دکھائیں"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"حسب ضرورت ٹرانسفارم فعال کریں"</string>
+ <string name="color_apply" msgid="9212602012641034283">"لاگو کریں"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"ترتیبات کی توثیق کریں"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"رنگوں کی کچھ ترتیبات اس آلے کو ناقابل استعمال بنا سکتی ہیں۔ رنگوں کی ان ترتیبات کی توثیق کرنے کیلئے ٹھیک ہے پر کلک کریں، بصورت دیگر 10 سیکنڈ بعد یہ ترتیبات ری سیٹ ہو جائیں گی۔"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index d011169..a849cfc 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -29,7 +29,7 @@
<item quantity="other">Umumiy ma’lumot bo‘limida %d ta ekran bor</item>
<item quantity="one">Umumiy ma’lumot bo‘limida 1 ta ekran bor</item>
</plurals>
- <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Eslatmalar - yo‘q"</string>
+ <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirishnomalar yo‘q"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Joriy"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Eslatmalar"</string>
<string name="battery_low_title" msgid="6456385927409742437">"Batareya quvvati kam"</string>
@@ -232,10 +232,10 @@
<string name="accessibility_clear_all" msgid="5235938559247164925">"Barcha eslatmalarni tozalash."</string>
<string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Bildirishnoma sozlamalari"</string>
<string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"<xliff:g id="APP_NAME">%s</xliff:g> sozlamalari"</string>
- <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik ravishda aylanadi."</string>
+ <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran avtomatik buriladi."</string>
<string name="accessibility_rotation_lock_on_landscape" msgid="6731197337665366273">"Ekran eniga holatida qulflandi."</string>
<string name="accessibility_rotation_lock_on_portrait" msgid="5809367521644012115">"Ekran bo‘yiga holatida qulflandi."</string>
- <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"Ekran endi avtomatik ravishda aylanadi."</string>
+ <string name="accessibility_rotation_lock_off_changed" msgid="8134601071026305153">"Ekran endi avtomatik buriladi."</string>
<string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ekran yotiq holatda aylanmaydigan qilindi."</string>
<string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ekran tik holatda aylanmaydigan qilindi."</string>
<string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
@@ -250,7 +250,7 @@
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth o‘chirilgan"</string>
<string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Ulangan qurilmalar topilmadi"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Yorqinlik"</string>
- <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Auto-aylantirish"</string>
+ <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Avtomatik burish"</string>
<string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Aylanmaydigan qilingan"</string>
<string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Bo‘yiga"</string>
<string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Eniga"</string>
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"qidirish"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"“<xliff:g id="APP">%s</xliff:g>” ilovasini ishga tushirib bo‘lmadi."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Ko‘proq"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Jurnal"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> ta"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Gorizontal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Vertikal yo‘nalishda bo‘lish"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Boshqa usulda bo‘lish"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Quvvat tejash rejimi yoqildi"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Unumdorlikni pasaytiradi va fonda int-dan foyd-ni cheklaydi"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Quvvat tejash funksiyasini o‘chiring"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Kontent yashirildi"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi qurilma ekranidagi har qanday tasvirni ko‘rishni boshlaydi."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Boshqa ko‘rsatilmasin"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Barchasini tozalash"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"“<xliff:g id="TOPIC_NAME">%1$s</xliff:g>” bildirishnomalariga qo‘llash"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Ushbu ilovaning barcha bildirishnomalariga qo‘llash"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bloklangan"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Kamroq muhim"</string>
+ <string name="default_importance" msgid="8192107689995742653">"O‘rtacha muhim"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Juda muhim"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Favqulodda muhim"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Odatiy ranglar"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Qoramtir ranglar"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Foydalanuvchi rangi"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Noma’lum ranglar"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Rang sozlamalari"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Tezkor sozlamalar panelini ko‘rsatish"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Foydalanuvchi sozlamalarini yoqish"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Qo‘llash"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Sozlamalarni tasdiqlang"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Ba’zi rang sozlamalari qurilmadan foydalanishni qiyinlashtirish mumkin. Tanlgan parametrlarni tasdiqlash uchun “OK” tugmasini bosing. Aks holda, ular 10 soniyadan so‘ng qayta tiklanadi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 81b5129..fa835ba 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"tìm kiếm"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Không thể khởi động <xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Thêm"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Lịch sử"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> tác vụ khác"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Phân tách ngang"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Phân tách dọc"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Tùy chỉnh phân tách"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Trình tiết kiệm pin đang bật"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Giảm hiệu suất và dữ liệu nền"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Tắt trình tiết kiệm pin"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Nội dung bị ẩn"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ bắt đầu chụp mọi thứ hiển thị trên màn hình."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Không hiển thị lại"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Xóa tất cả"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bật"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Áp dụng cho thông báo <xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Áp dụng cho tất cả thông báo từ ứng dụng này"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Bị chặn"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Tầm quan trọng thấp"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Tầm quan trọng bình thường"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Tầm quan trọng cao"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Tầm quan trọng khẩn cấp"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Không bao giờ hiển thị các thông báo này"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Hiển thị im lặng ở cuối danh sách thông báo"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Hiển thị im lặng các thông báo này"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Xong"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Màu thông thường"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Màu tối"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Màu tùy chỉnh"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Màu không xác định"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Sửa đổi màu"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Hiển thị ô Cài đặt nhanh"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Bật chuyển đổi tùy chỉnh"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Áp dụng"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Xác nhận cài đặt"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Một số cài đặt màu có thể khiến thiết bị này không sử dụng được. Hãy nhấp vào OK để xác nhận các cài đặt màu này, nếu không những cài đặt này sẽ được đặt lại sau 10 giây."</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e06052e..bb8f4ad 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜索"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"无法启动<xliff:g id="APP">%s</xliff:g>。"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"更多"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"历史记录"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"还有 <xliff:g id="NUMBER">%d</xliff:g> 项"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自定义分割"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"节电助手已开启"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低性能并限制后台流量"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"关闭节电助手"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"内容已隐藏"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>将开始截取您的屏幕上显示的所有内容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不再显示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -414,7 +413,7 @@
<string name="system_ui_tuner" msgid="708224127392452018">"系统界面调谐器"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"嵌入式显示电池电量百分比 显示嵌入的电池电量百分比"</string>
<string name="show_battery_percentage_summary" msgid="3215025775576786037">"未充电时在状态栏图标内显示电池电量百分比"</string>
- <string name="quick_settings" msgid="10042998191725428">"快速设置"</string>
+ <string name="quick_settings" msgid="10042998191725428">"快捷设置"</string>
<string name="status_bar" msgid="4877645476959324760">"状态栏"</string>
<string name="overview" msgid="4018602013895926956">"概览"</string>
<string name="demo_mode" msgid="2389163018533514619">"演示模式"</string>
@@ -430,7 +429,7 @@
<string name="zen_alarm_warning" msgid="444533119582244293">"您在<xliff:g id="WHEN">%1$s</xliff:g>将不会听到下次闹钟响铃"</string>
<string name="alarm_template" msgid="3980063409350522735">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template_far" msgid="4242179982586714810">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
- <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"快速设置,<xliff:g id="TITLE">%s</xliff:g>。"</string>
+ <string name="accessibility_quick_settings_detail" msgid="2579369091672902101">"快捷设置,<xliff:g id="TITLE">%s</xliff:g>。"</string>
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"热点"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"工作资料"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"是否有趣完全取决于个人感觉"</string>
@@ -443,10 +442,36 @@
<string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
<string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
- <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速设置"</string>
- <string name="show_brightness" msgid="6613930842805942519">"在快速设置中显示亮度栏"</string>
+ <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快捷设置"</string>
+ <string name="show_brightness" msgid="6613930842805942519">"在快捷设置中显示亮度栏"</string>
<string name="experimental" msgid="6198182315536726162">"实验性"</string>
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"应用于<xliff:g id="TOPIC_NAME">%1$s</xliff:g>通知"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"应用于来自此应用的所有通知"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"屏蔽"</string>
+ <string name="low_importance" msgid="4109929986107147930">"重要性:低"</string>
+ <string name="default_importance" msgid="8192107689995742653">"重要性:一般"</string>
+ <string name="high_importance" msgid="1527066195614050263">"重要性:高"</string>
+ <string name="max_importance" msgid="5089005872719563894">"重要性:紧急"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不显示这些通知"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"在通知列表底部显示,但不发出提示音"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"显示这些通知,但不发出提示音"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"在通知列表顶部显示,并发出提示音"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"在屏幕上持续显示,并发出提示音"</string>
+ <!-- no translation found for notification_more_settings (816306283396553571) -->
+ <skip />
+ <!-- no translation found for notification_done (5279426047273930175) -->
+ <skip />
+ <string name="color_matrix_none" msgid="2121957926040543148">"常规颜色"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"夜间颜色"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"自定义颜色"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"未知颜色"</string>
+ <string name="color_transform" msgid="6985460408079086090">"颜色修改"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"显示“快捷设置”图块"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"启用自定义转换"</string>
+ <string name="color_apply" msgid="9212602012641034283">"应用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"确认设置"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分颜色设置可能会导致此设备无法使用。请点击“确定”确认这些颜色设置,否则,系统将在 10 秒后重置这些设置。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 37d3ca6..0782354 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"更多"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"記錄"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"還有 <xliff:g id="NUMBER">%d</xliff:g> 項"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"省電模式已開啟"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉省電模式"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不用再顯示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"套用到此應用程式的所有通知"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"已封鎖"</string>
+ <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
+ <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
+ <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
+ <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部但不發出音效"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知但不發出音效"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂部並發出音效"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"不時於螢幕出現並發出音效"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
+ <string name="notification_done" msgid="5279426047273930175">"完成"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"一般色系"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"深沉色系"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"不明色系"</string>
+ <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示「快速設定」圖塊"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂變色功能"</string>
+ <string name="color_apply" msgid="9212602012641034283">"套用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定會令此裝置無法使用。請按一下 [確定] 加以確認,否則這些顏色設定將於 10 秒後重設。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 531b3cd..29520f6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"搜尋"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"無法啟動「<xliff:g id="APP">%s</xliff:g>」。"</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"更多"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"紀錄"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"還有 <xliff:g id="NUMBER">%d</xliff:g> 項"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"水平分割"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"垂直分割"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"自訂分割"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"節約耗電量模式已啟用"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"降低效能並限制背景數據傳輸"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"關閉節約耗電量模式"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"內容已隱藏"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 將開始擷取您的螢幕上顯示的內容。"</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"不要再顯示"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"全部清除"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"套用到「<xliff:g id="TOPIC_NAME">%1$s</xliff:g>」通知"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"套用到這個應用程式的所有通知"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"封鎖"</string>
+ <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
+ <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
+ <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
+ <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不顯示這些通知"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部且不發出任何音效"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知且不發出任何音效"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂端並發出音效"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"短暫顯示在螢幕上並發出音效"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
+ <string name="notification_done" msgid="5279426047273930175">"完成"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"一般顏色"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"夜間顏色"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"不明顏色"</string>
+ <string name="color_transform" msgid="6985460408079086090">"顏色修改"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"顯示快速設定圖塊"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"啟用自訂顏色變換"</string>
+ <string name="color_apply" msgid="9212602012641034283">"套用"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"確認設定"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"部分顏色設定可能會造成這部裝置無法使用。請按一下 [確定] 來確認您要使用這類顏色設定,否則系統將在 10 秒後重設這些設定。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b8e6a0f..3ee46ea 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -301,7 +301,7 @@
<string name="recents_search_bar_label" msgid="8074997400187836677">"sesha"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"Ayikwazanga ukuqala i-<xliff:g id="APP">%s</xliff:g>."</string>
<string name="recents_show_history_button_label" msgid="7062088196449747245">"Okuningi"</string>
- <string name="recents_history_label" msgid="3076213823382198287">"Umlando"</string>
+ <string name="recents_history_label_format" msgid="6337155608055062429">"<xliff:g id="NUMBER">%d</xliff:g> Okuningi"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Hlukanisa okuvundlile"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Hlukanisa okumile"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Hlukanisa kwezifiso"</string>
@@ -364,7 +364,6 @@
<string name="battery_saver_notification_title" msgid="237918726750955859">"Isilondolozi sebhethri sivuliwe"</string>
<string name="battery_saver_notification_text" msgid="820318788126672692">"Sehlisa ukusebenza nedatha yasemuva"</string>
<string name="battery_saver_notification_action_text" msgid="109158658238110382">"Vala isilondolozi sebhethri"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Okuqukethwe kufihliwe"</string>
<string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> izoqala ukuthwebula yonke into eboniswa kusikrini sakho."</string>
<string name="media_projection_remember_text" msgid="3103510882172746752">"Ungabonisi futhi"</string>
<string name="clear_all_notifications_text" msgid="814192889771462828">"Sula konke"</string>
@@ -449,4 +448,28 @@
<string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
<string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
<string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
+ <string name="apply_to_topic" msgid="3641403489318659666">"Sebenzisa kuzaziso ze-<xliff:g id="TOPIC_NAME">%1$s</xliff:g>"</string>
+ <string name="apply_to_app" msgid="363016783939815960">"Sebenzisa kuzo zonke izaziso ezivela kulolu hlelo lokusebenza"</string>
+ <string name="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</string>
+ <string name="low_importance" msgid="4109929986107147930">"Ukubaluleka okuphansi"</string>
+ <string name="default_importance" msgid="8192107689995742653">"Ukubaluleka okujwayelekile"</string>
+ <string name="high_importance" msgid="1527066195614050263">"Ukubaluleka okuphezulu"</string>
+ <string name="max_importance" msgid="5089005872719563894">"Ukubaluleka okusheshayo"</string>
+ <string name="notification_importance_blocked" msgid="2397192642657872872">"Ungalokothi ubonise lezi zaziso"</string>
+ <string name="notification_importance_low" msgid="4383563267370859725">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
+ <string name="notification_importance_default" msgid="4926529615920610817">"Bonisa ngokuthulile lezi zaziso"</string>
+ <string name="notification_importance_high" msgid="3222680136612408223">"Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
+ <string name="notification_importance_max" msgid="5236987171904756134">"Bheka kusikrini uphinde wenze umsindo"</string>
+ <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
+ <string name="color_matrix_none" msgid="2121957926040543148">"Imibala ejwayelekile"</string>
+ <string name="color_matrix_night" msgid="5943817622105307072">"Imibala yasebusuku"</string>
+ <string name="color_matrix_custom" msgid="3655576492322298713">"Imibala yangokwezifiso"</string>
+ <string name="color_matrix_unknown" msgid="2709202104256265107">"Imibala engaziwa"</string>
+ <string name="color_transform" msgid="6985460408079086090">"Ukulungiswa kombala"</string>
+ <string name="color_matrix_show_qs" msgid="1763244354399276679">"Bonisa ithayili lezilungiselelo ezisheshayo"</string>
+ <string name="color_enable_custom" msgid="6729001308217347501">"Nika amandla ukuguqulwa kwangokwezifiso"</string>
+ <string name="color_apply" msgid="9212602012641034283">"Sebenzisa"</string>
+ <string name="color_revert_title" msgid="4746666545480534663">"Qinisekisa izilungiselelo"</string>
+ <string name="color_revert_message" msgid="9116001069397996691">"Ezinye izilungiselelo zombala zingenza le divayisi ingasebenziseki. Chofoza ku-KULUNGILE ukuze uqinisekise lezi zilungiselelo zombala, uma kungenjalo lezi zilungiselelo zizosethwa kabusha ngemuva kwamasekhondi angu-10."</string>
</resources>
diff --git a/packages/SystemUI/res/values/arrays_car.xml b/packages/SystemUI/res/values/arrays_car.xml
new file mode 100644
index 0000000..230479d
--- /dev/null
+++ b/packages/SystemUI/res/values/arrays_car.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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>
+ <!-- These should be overriden in an overlay. The default implementation is empty.
+ There needs to be correspondence per index between these arrays, which means that if there
+ isn't a longpress action associated with a shortcut item, put in an empty item to make
+ sure everything lines up.
+ -->
+ <array name="car_shortcut_icons" />
+ <array name="car_shortcut_intent_uris" />
+ <array name="car_shortcut_longpress_intent_uris" />
+</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 94350d9..0ccc236 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -59,9 +59,9 @@
<!-- The recents task bar dark text color to be drawn on top of light backgrounds. -->
<color name="recents_task_bar_dark_text_color">#cc000000</color>
<!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. -->
- <color name="recents_task_bar_light_dismiss_color">#ffeeeeee</color>
+ <color name="recents_task_bar_light_icon_color">#ffeeeeee</color>
<!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. -->
- <color name="recents_task_bar_dark_dismiss_color">#99000000</color>
+ <color name="recents_task_bar_dark_icon_color">#99000000</color>
<!-- The recents task bar highlight color. -->
<color name="recents_task_bar_highlight_color">#28ffffff</color>
<!-- The lock to task button background color. -->
@@ -69,7 +69,7 @@
<!-- The lock to task button foreground color. -->
<color name="recents_task_view_lock_to_app_button_color">#ff666666</color>
<!-- The background color for the freeform workspace. -->
- <color name="recents_freeform_workspace_bg_color">#66000000</color>
+ <color name="recents_freeform_workspace_bg_color">#33FFFFFF</color>
<color name="keyguard_affordance">#ffffffff</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4f070d6..035f564 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -49,11 +49,14 @@
<dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
<!-- Height of a heads up notification in the status bar -->
- <dimen name="notification_max_heads_up_height">140dp</dimen>
+ <dimen name="notification_max_heads_up_height">141dp</dimen>
<!-- Height of a the summary ("more card") notification on keyguard. -->
<dimen name="notification_summary_height">44dp</dimen>
+ <!-- Minimum layouted height of a notification in the statusbar-->
+ <dimen name="min_notification_layout_height">48dp</dimen>
+
<!-- size at which Notification icons will be drawn in the status bar -->
<dimen name="status_bar_icon_drawing_size">17dip</dimen>
@@ -245,6 +248,9 @@
<!-- The height of the history button. -->
<dimen name="recents_history_button_height">48dp</dimen>
+ <!-- The padding between freeform workspace tasks -->
+ <dimen name="recents_freeform_workspace_task_padding">8dp</dimen>
+
<!-- Space reserved for the cards behind the top card in the top stack -->
<dimen name="top_stack_peek_amount">12dp</dimen>
@@ -577,9 +583,9 @@
<dimen name="qs_header_neg_padding">-8dp</dimen>
<!-- How high we lift the divider when touching -->
- <dimen name="docked_stack_divider_lift_elevation">6dp</dimen>
+ <dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
- <dimen name="docked_divider_handle_width">24dp</dimen>
+ <dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 666a024..876c21e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -713,8 +713,8 @@
<string name="recents_launch_error_message">Could not start <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
<!-- Recents: Show history string. [CHAR LIMIT=NONE] -->
<string name="recents_show_history_button_label">More</string>
- <!-- Recents: The history of recents. [CHAR LIMIT=NONE] -->
- <string name="recents_history_label">History</string>
+ <!-- Recents: A format string to set the number of availabe historical tasks in recents. [CHAR LIMIT=NONE] -->
+ <string name="recents_history_label_format"><xliff:g id="number">%d</xliff:g> More</string>
<!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string>
@@ -906,9 +906,6 @@
<!-- Battery saver notification action text. [CHAR LIMIT=60] -->
<string name="battery_saver_notification_action_text">Turn off battery saver</string>
- <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen -->
- <string name="notification_hidden_text">Contents hidden</string>
-
<!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
<string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything that\'s displayed on your screen.</string>
@@ -1171,31 +1168,11 @@
<!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
<string name="qs_paging" translatable="false">Use the new Quick Settings</string>
- <!-- Toggles paging recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_page_on_toggle">Enable paging</string>
- <!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
- <string name="overview_page_on_toggle_desc">Enable paging via the Overview button</string>
-
<!-- Toggles fast-toggling recents via the recents button. DO NOT TRANSLATE -->
<string name="overview_fast_toggle_via_button">Enable fast toggle</string>
<!-- Description for the toggle for fast-toggling recents via the recents button. DO NOT TRANSLATE -->
<string name="overview_fast_toggle_via_button_desc">Enable launch timeout while paging</string>
- <!-- Toggles fullscreen screenshots. DO NOT TRANSLATE -->
- <string name="overview_fullscreen_thumbnails">Enable fullscreen screenshots</string>
- <!-- Description for the toggle for fullscreen screenshots. DO NOT TRANSLATE -->
- <string name="overview_fullscreen_thumbnails_desc">Enable fullscreen screenshots in Overview. Restart required.</string>
-
- <!-- Toggle to enable the Overview nav bar gesture. DO NOT TRANSLATE -->
- <string name="overview_nav_bar_gesture">Enable navigation bar gesture</string>
- <!-- Description for the toggle to enable the Overview nav bar gesture. DO NOT TRANSLATE -->
- <string name="overview_nav_bar_gesture_desc">Enables the gesture to enter Overview by swiping up on the Nav bar</string>
-
- <!-- Toggle to show the history view in Overview. DO NOT TRANSLATE -->
- <string name="overview_show_history">Show History</string>
- <!-- Description for the toggle to show the history view in Overview. DO NOT TRANSLATE -->
- <string name="overview_show_history_desc">Enables the history view to see more recent tasks</string>
-
<!-- Toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
<string name="overview_initial_state_paging">Initialize to paging</string>
<!-- Description for the toggle to set the initial scroll state to be paging or stack. DO NOT TRANSLATE -->
@@ -1221,4 +1198,75 @@
<!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
<string name="enable_bluetooth_confirmation_ok">Turn on</string>
+ <!-- Apply notification importance setting to a topic [CHAR LIMIT=NONE] -->
+ <string name="apply_to_topic">Apply to <xliff:g id="topic_name" example="Friend Request">%1$s</xliff:g> notifications</string>
+ <!-- Apply notification importance setting to an app [CHAR LIMIT=NONE] -->
+ <string name="apply_to_app">Apply to all notifications from this app</string>
+ <!-- Notification importance title, blocked status-->
+ <string name="blocked_importance">Blocked</string>
+ <!-- Notification importance title, low status-->
+ <string name="low_importance">Low importance</string>
+ <!-- Notification importance title, normal status-->
+ <string name="default_importance">Normal importance</string>
+ <!-- Notification importance title, high status-->
+ <string name="high_importance">High importance</string>
+ <!-- Notification importance title, max status-->
+ <string name="max_importance">Urgent importance</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: blocked importance level description -->
+ <string name="notification_importance_blocked">Never show these notifications</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: low importance level description -->
+ <string name="notification_importance_low">Silently show at the bottom of the notification list</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: normal importance level description -->
+ <string name="notification_importance_default">Silently show these notifications</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: high importance level description -->
+ <string name="notification_importance_high">Show at the top of the notifications list and make sound</string>
+
+ <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
+ <string name="notification_importance_max">Peek onto the screen and make sound</string>
+
+ <!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
+ <string name="notification_more_settings">More settings</string>
+ <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
+ <string name="notification_done">Done</string>
+
+ <!-- Label for no color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_none">Normal colors</string>
+
+ <!-- Label for night color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_night">Night colors</string>
+
+ <!-- Label for custom color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_custom">Custom colors</string>
+
+ <!-- Label for unknown color transform [CHAR LIMIT=30] -->
+ <string name="color_matrix_unknown">Unknown colors</string>
+
+ <!-- Title for color transform [CHAR LIMIT=30] -->
+ <string name="color_transform">Color modification</string>
+
+ <!-- Title for setting to show Quick Settings tile [CHAR LIMIT=60] -->
+ <string name="color_matrix_show_qs">Show Quick Settings tile</string>
+
+ <!-- Title for switch to enable custom color transform [CHAR LIMIT=60] -->
+ <string name="color_enable_custom">Enable custom transform</string>
+
+ <!-- Button to apply settings [CHAR LIMIT=30] -->
+ <string name="color_apply">Apply</string>
+
+ <!-- Title of warning dialog about bad color settings. [CHAR LIMIT=30] -->
+ <string name="color_revert_title">Confirm settings</string>
+
+ <!-- Message warning user about custom color settings [CHAR LIMIT=NONE] -->
+ <string name="color_revert_message">Some color settings can make this
+ device unusable. Click OK to confirm these color settings,
+ otherwise these settings will reset after 10 seconds.</string>
+
+ <string name="color_modification_r" translatable="false">R</string>
+ <string name="color_modification_g" translatable="false">G</string>
+ <string name="color_modification_b" translatable="false">B</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 47ad6dc..527b638 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -237,12 +237,6 @@
<item name="android:gravity">center</item>
</style>
- <style name="TextAppearance.Material.Notification.Parenthetical"
- parent="@*android:style/TextAppearance.Material.Notification">
- <item name="android:textStyle">italic</item>
- <item name="android:textColor">#60000000</item>
- </style>
-
<style name="TextAppearance.Material.Notification.HeaderTitle"
parent="@*android:style/TextAppearance.Material.Notification.Info">
</style>
@@ -305,14 +299,30 @@
<style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">12dp</item>
+ <item name="android:layout_height">10dp</item>
<item name="android:layout_gravity">center_vertical</item>
</style>
<style name="DockedDividerHandle">
<item name="android:layout_gravity">center_horizontal</item>
- <item name="android:layout_width">64dp</item>
+ <item name="android:layout_width">96dp</item>
<item name="android:layout_height">48dp</item>
</style>
+ <style name="TunerSettings" parent="@android:style/Theme.Material.Settings">
+ <item name="preferenceTheme">@style/TunerPreferenceTheme</item>
+ </style>
+
+ <style name="TunerPreferenceTheme" parent="@android:style/Theme.Material.Settings">
+ <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
+ </style>
+
+ <style name="TextAppearance.NotificationGuts">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@color/notification_guts_btn_color</item>
+ <item name="android:textAllCaps">true</item>
+ <item name="android:fontFamily">sans-serif-medium</item>
+ <item name="android:gravity">center</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index e31927e..f02f763 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -24,6 +24,7 @@
sysui:defValue="true" />
<PreferenceScreen
+ android:key="status_bar"
android:title="@string/status_bar" >
<com.android.systemui.tuner.StatusBarSwitch
@@ -70,14 +71,10 @@
<PreferenceScreen
+ android:key="overview"
android:title="@string/overview" >
<com.android.systemui.tuner.TunerSwitch
- android:key="overview_page_on_toggle"
- android:title="@string/overview_page_on_toggle"
- android:summary="@string/overview_page_on_toggle_desc" />
-
- <com.android.systemui.tuner.TunerSwitch
android:key="overview_initial_state_paging"
android:title="@string/overview_initial_state_paging"
android:summary="@string/overview_initial_state_paging_desc" />
@@ -87,21 +84,6 @@
android:title="@string/overview_fast_toggle_via_button"
android:summary="@string/overview_fast_toggle_via_button_desc" />
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_nav_bar_gesture"
- android:title="@string/overview_nav_bar_gesture"
- android:summary="@string/overview_nav_bar_gesture_desc" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_fullscreen_thumbnails"
- android:title="@string/overview_fullscreen_thumbnails"
- android:summary="@string/overview_fullscreen_thumbnails_desc" />
-
- <com.android.systemui.tuner.TunerSwitch
- android:key="overview_show_history"
- android:title="@string/overview_show_history"
- android:summary="@string/overview_show_history_desc" />
-
</PreferenceScreen>
<SwitchPreference
@@ -117,7 +99,13 @@
<Preference
android:key="demo_mode"
- android:title="@string/demo_mode" />
+ android:title="@string/demo_mode"
+ android:fragment="com.android.systemui.tuner.DemoModeFragment" />
+
+ <Preference
+ android:key="color_transform"
+ android:title="@string/color_transform"
+ android:fragment="com.android.systemui.tuner.ColorMatrixFragment" />
<!-- Warning, this goes last. -->
<Preference
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index d931856..481b9180 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -70,17 +70,19 @@
// time for us to receive the signal that it's starting.
private static final long BLUETOOTH_START_DELAY_MILLIS = 10 * 1000;
+ // We will be scanning up to 30 seconds, after which we'll stop.
+ private static final long BLUETOOTH_SCAN_TIMEOUT_MILLIS = 30 * 1000;
+
private static final int STATE_NOT_ENABLED = -1;
private static final int STATE_UNKNOWN = 0;
private static final int STATE_WAITING_FOR_BOOT_COMPLETED = 1;
private static final int STATE_WAITING_FOR_TABLET_MODE_EXIT = 2;
private static final int STATE_WAITING_FOR_DEVICE_DISCOVERY = 3;
private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
- private static final int STATE_WAITING_FOR_STATE_PAIRED = 5;
- private static final int STATE_PAIRING = 6;
- private static final int STATE_PAIRED = 7;
- private static final int STATE_USER_CANCELLED = 8;
- private static final int STATE_DEVICE_NOT_FOUND = 9;
+ private static final int STATE_PAIRING = 5;
+ private static final int STATE_PAIRED = 6;
+ private static final int STATE_USER_CANCELLED = 7;
+ private static final int STATE_DEVICE_NOT_FOUND = 8;
private static final int MSG_INIT = 0;
private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -92,6 +94,7 @@
private static final int MSG_ON_BLE_SCAN_FAILED = 7;
private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
+ private static final int MSG_BLE_ABORT_SCAN = 10;
private volatile KeyboardHandler mHandler;
private volatile KeyboardUIHandler mUIHandler;
@@ -107,6 +110,7 @@
private long mBootCompletedTime;
private int mInTabletMode = InputManager.SWITCH_STATE_UNKNOWN;
+ private int mScanAttempt = 0;
private ScanCallback mScanCallback;
private BluetoothDialog mDialog;
@@ -328,6 +332,9 @@
.build();
mScanCallback = new KeyboardScanCallback();
scanner.startScan(Arrays.asList(filter), settings, mScanCallback);
+
+ Message abortMsg = mHandler.obtainMessage(MSG_BLE_ABORT_SCAN, ++mScanAttempt, 0);
+ mHandler.sendMessageDelayed(abortMsg, BLUETOOTH_SCAN_TIMEOUT_MILLIS);
}
private void stopScanning() {
@@ -338,6 +345,19 @@
}
// Should only be called on the handler thread
+ private void bleAbortScanInternal(int scanAttempt) {
+ if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && scanAttempt == mScanAttempt) {
+ if (DEBUG) {
+ Slog.d(TAG, "Bluetooth scan timed out");
+ }
+ stopScanning();
+ // FIXME: should we also try shutting off bluetooth if we enabled
+ // it in the first place?
+ mState = STATE_DEVICE_NOT_FOUND;
+ }
+ }
+
+ // Should only be called on the handler thread
private void onDeviceAddedInternal(CachedBluetoothDevice d) {
if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY && d.getName().equals(mKeyboardName)) {
stopScanning();
@@ -425,6 +445,12 @@
} else {
mState = STATE_USER_CANCELLED;
}
+ break;
+ }
+ case MSG_BLE_ABORT_SCAN: {
+ int scanAttempt = msg.arg1;
+ bleAbortScanInternal(scanAttempt);
+ break;
}
case MSG_ON_BLUETOOTH_STATE_CHANGED: {
int bluetoothState = msg.arg1;
@@ -555,8 +581,6 @@
return "STATE_WAITING_FOR_DEVICE_DISCOVERY";
case STATE_WAITING_FOR_BLUETOOTH:
return "STATE_WAITING_FOR_BLUETOOTH";
- case STATE_WAITING_FOR_STATE_PAIRED:
- return "STATE_WAITING_FOR_STATE_PAIRED";
case STATE_PAIRING:
return "STATE_PAIRING";
case STATE_PAIRED:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index b56ad76..01eb5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -75,7 +75,8 @@
iv.setTag(R.id.qs_icon_tag, state.icon);
if (d instanceof Animatable) {
Animatable a = (Animatable) d;
- if (state.icon instanceof QSTile.AnimationIcon && !iv.isShown()) {
+ a.start();
+ if (!iv.isShown()) {
a.stop(); // skip directly to end state
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39f0c55..1a36abd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,8 +19,6 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
@@ -29,9 +27,20 @@
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-
import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.*;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
import java.util.Collection;
import java.util.Objects;
@@ -389,11 +398,7 @@
@Override
public Drawable getDrawable(Context context) {
- Drawable d = context.getDrawable(mResId);
- if (d instanceof Animatable) {
- ((Animatable) d).start();
- }
- return d;
+ return context.getDrawable(mResId);
}
@Override
@@ -408,41 +413,14 @@
}
protected class AnimationIcon extends ResourceIcon {
- private boolean mAllowAnimation;
-
public AnimationIcon(int resId) {
super(resId);
}
- public void setAllowAnimation(boolean allowAnimation) {
- mAllowAnimation = allowAnimation;
- }
-
@Override
public Drawable getDrawable(Context context) {
// workaround: get a clean state for every new AVD
- final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
- .getConstantState().newDrawable();
- d.start();
- if (mAllowAnimation) {
- mAllowAnimation = false;
- } else {
- d.stop(); // skip directly to end state
- }
- return d;
- }
- }
-
- protected enum UserBoolean {
- USER_TRUE(true, true),
- USER_FALSE(true, false),
- BACKGROUND_TRUE(false, true),
- BACKGROUND_FALSE(false, false);
- public final boolean value;
- public final boolean userInitiated;
- private UserBoolean(boolean userInitiated, boolean value) {
- this.value = value;
- this.userInitiated = userInitiated;
+ return context.getDrawable(mResId).getConstantState().newDrawable();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
deleted file mode 100644
index a5e1fd5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.android.systemui.qs;
-
-import android.os.IBinder;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-
-
-public class QSTileServiceWrapper implements IQSTileService {
- private static final String TAG = "IQSTileServiceWrapper";
-
- private final IQSTileService mService;
-
- public QSTileServiceWrapper(IQSTileService service) {
- mService = service;
- }
-
- @Override
- public IBinder asBinder() {
- return mService.asBinder();
- }
-
- @Override
- public void setQSTile(Tile tile) {
- try {
- mService.setQSTile(tile);
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onTileAdded() {
- try {
- mService.onTileAdded();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onTileRemoved() {
- try {
- mService.onTileRemoved();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onStartListening() {
- try {
- mService.onStartListening();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onStopListening() {
- try {
- mService.onStopListening();
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-
- @Override
- public void onClick(IBinder token) {
- try {
- mService.onClick(token);
- } catch (Exception e) {
- Log.d(TAG, "Caught exception from QSTileService", e);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index bda4675..5fa38c6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -49,6 +49,11 @@
mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
}
+ @Override
+ protected void createCustomizePanel() {
+ // No customizing from the header.
+ }
+
public void setQSPanelAndHeader(QSPanel fullPanel, View header) {
mFullPanel = fullPanel;
mHeader = header;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 87c29735..7448493 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -16,32 +16,28 @@
package com.android.systemui.qs.customize;
import android.app.ActivityManager;
-import android.app.Service;
import android.content.ClipData;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
+import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings.Secure;
-import android.service.quicksettings.IQSTileService;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
-
import com.android.systemui.R;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileLifecycleManager;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
/**
@@ -52,8 +48,9 @@
public class CustomQSPanel extends QSPanel {
private static final String TAG = "CustomQSPanel";
+ private static final boolean DEBUG = false;
- private List<String> mSavedTiles;
+ private List<String> mSavedTiles = Collections.emptyList();
private ArrayList<String> mStash;
private List<String> mTiles = new ArrayList<>();
@@ -67,17 +64,25 @@
((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this);
removeView(mFooter.getView());
+ if (DEBUG) Log.d(TAG, "new CustomQSPanel", new Throwable());
TunerService.get(mContext).addTunable(this, QSTileHost.TILES_SETTING);
}
@Override
+ protected void onDetachedFromWindow() {
+ // Don't allow the super to unregister the tunable.
+ }
+
+ @Override
public void onTuningChanged(String key, String newValue) {
if (key.equals(QS_SHOW_BRIGHTNESS)) {
// No Brightness for you.
super.onTuningChanged(key, "0");
}
if (QSTileHost.TILES_SETTING.equals(key)) {
- mSavedTiles = QSTileHost.loadTileSpecs(mContext, newValue);
+ mSavedTiles = Collections.unmodifiableList(
+ QSTileHost.loadTileSpecs(mContext, newValue));
+ if (DEBUG) Log.d(TAG, "New saved tiles " + TextUtils.join(",", mSavedTiles));
}
}
@@ -106,6 +111,7 @@
}
public void setSavedTiles() {
+ if (DEBUG) Log.d(TAG, "setSavedTiles " + TextUtils.join(",", mSavedTiles));
setTiles(mSavedTiles);
}
@@ -114,47 +120,26 @@
String tileSpec = mSavedTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!mTiles.contains(tileSpec)) {
- mContext.bindServiceAsUser(
- new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
- new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
- IQSTileService.Stub.asInterface(service));
- wrapper.onStopListening();
- wrapper.onTileRemoved();
- mContext.unbindService(this);
- }
- }, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
+ Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+ TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+ mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ lifecycleManager.onStopListening();
+ lifecycleManager.onTileRemoved();
+ lifecycleManager.flushMessagesAndUnbind();
}
}
for (int i = 0; i < mTiles.size(); i++) {
String tileSpec = mTiles.get(i);
if (!tileSpec.startsWith(CustomTile.PREFIX)) continue;
if (!mSavedTiles.contains(tileSpec)) {
- mContext.bindServiceAsUser(
- new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)),
- new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- QSTileServiceWrapper wrapper = new QSTileServiceWrapper(
- IQSTileService.Stub.asInterface(service));
- wrapper.onTileAdded();
- mContext.unbindService(this);
- }
- }, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
+ Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec));
+ TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(),
+ mContext, intent, new UserHandle(ActivityManager.getCurrentUser()));
+ lifecycleManager.onTileAdded();
+ lifecycleManager.flushMessagesAndUnbind();
}
}
+ if (DEBUG) Log.d(TAG, "saveCurrentTiles " + mTiles);
Secure.putStringForUser(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
TextUtils.join(",", mTiles), ActivityManager.getCurrentUser());
}
@@ -173,30 +158,37 @@
}
private void setTilesInternal() {
+ if (DEBUG) Log.d(TAG, "Set tiles internal");
for (int i = 0; i < mCurrentTiles.size(); i++) {
mCurrentTiles.get(i).destroy();
}
mCurrentTiles.clear();
for (int i = 0; i < mTiles.size(); i++) {
if (mTiles.get(i).startsWith(CustomTile.PREFIX)) {
- mCurrentTiles.add(BlankCustomTile.create(mHost, mTiles.get(i)));
+ QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i));
+ tile.setTileSpec(mTiles.get(i));
+ mCurrentTiles.add(tile);
} else {
QSTile<?> tile = mHost.createTile(mTiles.get(i));
if (tile != null) {
+ tile.setTileSpec(mTiles.get(i));
mCurrentTiles.add(tile);
+ } else {
+ if (DEBUG) Log.d(TAG, "Skipping " + mTiles.get(i));
}
}
- mCurrentTiles.get(mCurrentTiles.size() - 1).setTileSpec(mTiles.get(i));
}
super.setTiles(mCurrentTiles);
}
public void addTile(String spec) {
+ if (DEBUG) Log.d(TAG, "addTile " + spec);
mTiles.add(spec);
setTilesInternal();
}
public void moveTo(String from, String to) {
+ if (DEBUG) Log.d(TAG, "moveTo " + from + " " + to);
int fromIndex = mTiles.indexOf(from);
if (fromIndex < 0) {
Log.e(TAG, "Unknown from tile " + from);
@@ -220,6 +212,7 @@
}
public void setTiles(List<String> tiles) {
+ if (DEBUG) Log.d(TAG, "Set tiles " + TextUtils.join(",", tiles));
mTiles = new ArrayList<>(tiles);
setTilesInternal();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 6706c7a..a6a7143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,7 @@
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
import com.android.systemui.qs.QSTile.Icon;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.statusbar.phone.QSTileHost;
import com.android.systemui.tuner.QSPagingSwitch;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
rename to packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index bb74f34..2e5a0b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -11,32 +11,26 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT 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.systemui.qs.external;
-package com.android.systemui.qs.tiles;
-
-import android.app.ActivityManager;
-import android.app.Service;
import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
import com.android.systemui.statusbar.phone.QSTileHost;
public class CustomTile extends QSTile<QSTile.State> {
@@ -52,8 +46,9 @@
private final Tile mTile;
private final IWindowManager mWindowManager;
private final IBinder mToken = new Binder();
+ private final IQSTileService mService;
+ private final TileServiceManager mServiceManager;
- private QSTileServiceWrapper mService;
private boolean mListening;
private boolean mBound;
private boolean mIsTokenGranted;
@@ -63,7 +58,9 @@
super(host);
mWindowManager = WindowManagerGlobal.getWindowManagerService();
mComponent = ComponentName.unflattenFromString(action);
- mTile = new Tile(mComponent, host);
+ mServiceManager = host.getTileServices().getTileWrapper(this);
+ mService = mServiceManager.getTileService();
+ mTile = new Tile(mComponent);
try {
PackageManager pm = mContext.getPackageManager();
ServiceInfo info = pm.getServiceInfo(mComponent, 0);
@@ -72,6 +69,11 @@
mTile.setLabel(info.loadLabel(pm));
} catch (Exception e) {
}
+ try {
+ mService.setQSTile(mTile);
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
+ }
}
public ComponentName getComponent() {
@@ -96,42 +98,33 @@
public void setListening(boolean listening) {
if (mListening == listening) return;
mListening = listening;
- if (listening) {
- mHandler.removeCallbacks(mUnbind);
- if (!mBound) {
- // TODO: Guarantee re-bind on user-switch.
- mContext.bindServiceAsUser(new Intent().setComponent(mComponent),
- mServiceConnection, Service.BIND_AUTO_CREATE,
- new UserHandle(ActivityManager.getCurrentUser()));
- mBound = true;
- } else {
- if (mService != null) {
+ try {
+ if (listening) {
+ if (mServiceManager.getType() == TileService.TILE_MODE_PASSIVE) {
+ mServiceManager.setBindRequested(true);
mService.onStartListening();
- } else {
- Log.d(TAG, "Can't start service listening");
}
- }
- } else {
- if (mService != null) {
+ } else {
mService.onStopListening();
- }
- if (mIsTokenGranted && !mIsShowingDialog) {
- try {
- if (DEBUG) Log.d(TAG, "Removing token");
- mWindowManager.removeWindowToken(mToken);
- } catch (RemoteException e) {
+ if (mIsTokenGranted && !mIsShowingDialog) {
+ try {
+ if (DEBUG) Log.d(TAG, "Removing token");
+ mWindowManager.removeWindowToken(mToken);
+ } catch (RemoteException e) {
+ }
+ mIsTokenGranted = false;
}
- mIsTokenGranted = false;
+ mIsShowingDialog = false;
+ mServiceManager.setBindRequested(false);
}
- mIsShowingDialog = false;
- mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
}
}
@Override
protected void handleDestroy() {
super.handleDestroy();
- mHandler.removeCallbacks(mUnbind);
if (mIsTokenGranted) {
try {
if (DEBUG) Log.d(TAG, "Removing token");
@@ -139,7 +132,6 @@
} catch (RemoteException e) {
}
}
- mUnbind.run();
}
@Override
@@ -154,16 +146,20 @@
@Override
protected void handleClick() {
- if (mService != null) {
- try {
- if (DEBUG) Log.d(TAG, "Adding token");
- mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
- mIsTokenGranted = true;
- } catch (RemoteException e) {
+ try {
+ if (DEBUG) Log.d(TAG, "Adding token");
+ mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
+ mIsTokenGranted = true;
+ } catch (RemoteException e) {
+ }
+ try {
+ if (mServiceManager.getType() == TileService.TILE_MODE_ACTIVE) {
+ mServiceManager.setBindRequested(true);
+ mService.onStartListening();
}
mService.onClick(mToken);
- } else {
- Log.e(TAG, "Click with no service " + getTileSpec());
+ } catch (RemoteException e) {
+ // Called through wrapper, won't happen here.
}
MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
}
@@ -187,34 +183,9 @@
@Override
public int getMetricsCategory() {
- return MetricsLogger.QS_INTENT;
+ return MetricsLogger.QS_CUSTOM;
}
- private final ServiceConnection mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mService = new QSTileServiceWrapper(IQSTileService.Stub.asInterface(service));
- if (mListening) {
- mService.setQSTile(mTile);
- mService.onStartListening();
- } else {
- mService.onStopListening();
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- }
- };
-
- private final Runnable mUnbind = new Runnable() {
- @Override
- public void run() {
- mContext.unbindService(mServiceConnection);
- mBound = false;
- }
- };
-
public static ComponentName getComponentFromSpec(String spec) {
final String action = spec.substring(PREFIX.length(), spec.length() - 1);
if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
new file mode 100644
index 0000000..d41cdde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.os.IBinder;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.util.Log;
+
+
+public class QSTileServiceWrapper {
+ private static final String TAG = "IQSTileServiceWrapper";
+
+ private final IQSTileService mService;
+
+ public QSTileServiceWrapper(IQSTileService service) {
+ mService = service;
+ }
+
+ public IBinder asBinder() {
+ return mService.asBinder();
+ }
+
+ public boolean setQSTile(Tile tile) {
+ try {
+ mService.setQSTile(tile);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onTileAdded() {
+ try {
+ mService.onTileAdded();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onTileRemoved() {
+ try {
+ mService.onTileRemoved();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onStartListening() {
+ try {
+ mService.onStartListening();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onStopListening() {
+ try {
+ mService.onStopListening();
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean onClick(IBinder token) {
+ try {
+ mService.onClick(token);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+
+ public boolean setQSService(IQSService service) {
+ try {
+ mService.setQSService(service);
+ return true;
+ } catch (Exception e) {
+ Log.d(TAG, "Caught exception from TileService", e);
+ return false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
new file mode 100644
index 0000000..8c5e87e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.Log;
+import libcore.util.Objects;
+
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of a TileService.
+ * <p>
+ * Will keep track of all calls on the IQSTileService interface and will relay those calls to the
+ * TileService as soon as it is bound. It will only bind to the service when it is allowed to
+ * ({@link #setBindService(boolean)}) and when the service is available.
+ */
+public class TileLifecycleManager extends BroadcastReceiver implements
+ IQSTileService, ServiceConnection, IBinder.DeathRecipient {
+ public static final boolean DEBUG = false;
+
+ private static final String TAG = "TileLifecycleManager";
+
+ private static final int MSG_ON_ADDED = 0;
+ private static final int MSG_ON_REMOVED = 1;
+ private static final int MSG_ON_CLICK = 2;
+
+ // Bind retry control.
+ private static final int MAX_BIND_RETRIES = 5;
+ private static final int BIND_RETRY_DELAY = 1000;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Intent mIntent;
+ private final UserHandle mUser;
+
+ private Set<Integer> mQueuedMessages = new ArraySet<>();
+ private QSTileServiceWrapper mWrapper;
+ private boolean mListening;
+ private Tile mTile;
+ private IBinder mClickBinder;
+
+ private int mBindTryCount;
+ private boolean mBound;
+ @VisibleForTesting
+ boolean mReceiverRegistered;
+ private IQSService mService;
+ private boolean mUnbindImmediate;
+
+ public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+ mContext = context;
+ mHandler = handler;
+ mIntent = intent;
+ mUser = user;
+ }
+
+ public ComponentName getComponent() {
+ return mIntent.getComponent();
+ }
+
+ public boolean hasPendingClick() {
+ synchronized (mQueuedMessages) {
+ return mQueuedMessages.contains(MSG_ON_CLICK);
+ }
+ }
+
+ /**
+ * Binds just long enough to send any queued messages, then unbinds.
+ */
+ public void flushMessagesAndUnbind() {
+ mUnbindImmediate = true;
+ setBindService(true);
+ }
+
+ public void setBindService(boolean bind) {
+ mBound = bind;
+ if (bind) {
+ if (mBindTryCount == MAX_BIND_RETRIES) {
+ // Too many failures, give up on this tile until an update.
+ startPackageListening();
+ return;
+ }
+ if (!checkComponentState()) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+ mBindTryCount++;
+ mContext.bindServiceAsUser(mIntent, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+ mUser);
+ } else {
+ if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent);
+ // Give it another chance next time it needs to be bound, out of kindness.
+ mBindTryCount = 0;
+ mWrapper = null;
+ mContext.unbindService(this);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+ // Got a connection, set the binding count to 0.
+ mBindTryCount = 0;
+ mWrapper = new QSTileServiceWrapper(Stub.asInterface(service));
+ try {
+ service.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ }
+ setQSService(mService);
+ setQSTile(mTile);
+ handlePendingMessages();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+ mWrapper = null;
+ }
+
+ private void handlePendingMessages() {
+ // This ordering is laid out manually to make sure we preserve the TileService
+ // lifecycle.
+ ArraySet<Integer> queue;
+ synchronized (mQueuedMessages) {
+ queue = new ArraySet<>(mQueuedMessages);
+ mQueuedMessages.clear();
+ }
+ if (queue.contains(MSG_ON_ADDED)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+ onTileAdded();
+ }
+ if (mListening) {
+ if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+ onStartListening();
+ }
+ if (queue.contains(MSG_ON_CLICK)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onClick");
+ if (!mListening) {
+ Log.w(TAG, "Managed to get click on non-listening state...");
+ // Skipping click since lost click privileges.
+ } else {
+ onClick(mClickBinder);
+ }
+ }
+ if (queue.contains(MSG_ON_REMOVED)) {
+ if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+ if (mListening) {
+ Log.w(TAG, "Managed to get remove in listening state...");
+ onStopListening();
+ }
+ onTileRemoved();
+ }
+ if (mUnbindImmediate) {
+ mUnbindImmediate = false;
+ setBindService(false);
+ }
+ }
+
+ public void handleDestroy() {
+ if (DEBUG) Log.d(TAG, "handleDestroy");
+ if (mReceiverRegistered) {
+ stopPackageListening();
+ }
+ }
+
+ private void handleDeath() {
+ if (mWrapper == null) return;
+ mWrapper = null;
+ if (!mBound) return;
+ if (DEBUG) Log.d(TAG, "handleDeath");
+ if (checkComponentState()) {
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (mBound) {
+ // Retry binding.
+ setBindService(true);
+ }
+ }
+ }, BIND_RETRY_DELAY);
+ }
+ }
+
+ @Override
+ public void setQSTile(Tile tile) {
+ if (DEBUG) Log.d(TAG, "setQSTile " + tile);
+ mTile = tile;
+ if (mWrapper != null && !mWrapper.setQSTile(tile)) {
+ handleDeath();
+ }
+ }
+
+ private boolean checkComponentState() {
+ PackageManager pm = mContext.getPackageManager();
+ if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+ startPackageListening();
+ return false;
+ }
+ return true;
+ }
+
+ private void startPackageListening() {
+ if (DEBUG) Log.d(TAG, "startPackageListening");
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+ mReceiverRegistered = true;
+ }
+
+ private void stopPackageListening() {
+ if (DEBUG) Log.d(TAG, "stopPackageListening");
+ mContext.unregisterReceiver(this);
+ mReceiverRegistered = false;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) Log.d(TAG, "onReceive: " + intent);
+ Uri data = intent.getData();
+ String pkgName = data.getEncodedSchemeSpecificPart();
+ if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
+ return;
+ }
+ stopPackageListening();
+ if (mBound) {
+ // Trying to bind again will check the state of the package before bothering to bind.
+ if (DEBUG) Log.d(TAG, "Trying to rebind");
+ setBindService(true);
+ }
+ }
+
+ private boolean isComponentAvailable(PackageManager pm) {
+ String packageName = mIntent.getComponent().getPackageName();
+ try {
+ ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+ 0, mUser.getIdentifier());
+ if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+ return si != null;
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ }
+ return false;
+ }
+
+ private boolean isPackageAvailable(PackageManager pm) {
+ String packageName = mIntent.getComponent().getPackageName();
+ try {
+ pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
+ else Log.d(TAG, "Package not available: " + packageName);
+ }
+ return false;
+ }
+
+ private void queueMessage(int message) {
+ synchronized (mQueuedMessages) {
+ mQueuedMessages.add(message);
+ }
+ }
+
+ @Override
+ public void setQSService(IQSService service) {
+ mService = service;
+ if (mWrapper == null || !mWrapper.setQSService(service)) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onTileAdded() {
+ if (DEBUG) Log.d(TAG, "onTileAdded");
+ if (mWrapper == null || !mWrapper.onTileAdded()) {
+ queueMessage(MSG_ON_ADDED);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onTileRemoved() {
+ if (DEBUG) Log.d(TAG, "onTileRemoved");
+ if (mWrapper == null || !mWrapper.onTileRemoved()) {
+ queueMessage(MSG_ON_REMOVED);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onStartListening() {
+ if (DEBUG) Log.d(TAG, "onStartListening");
+ mListening = true;
+ if (mWrapper != null && !mWrapper.onStartListening()) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onStopListening() {
+ if (DEBUG) Log.d(TAG, "onStopListening");
+ mListening = false;
+ if (mWrapper != null && !mWrapper.onStopListening()) {
+ handleDeath();
+ }
+ }
+
+ @Override
+ public void onClick(IBinder iBinder) {
+ if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+ if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+ mClickBinder = iBinder;
+ queueMessage(MSG_ON_CLICK);
+ handleDeath();
+ }
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return mWrapper != null ? mWrapper.asBinder() : null;
+ }
+
+ @Override
+ public void binderDied() {
+ if (DEBUG) Log.d(TAG, "binderDeath");
+ handleDeath();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
new file mode 100644
index 0000000..2f77a30
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.TileService;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+/**
+ * Manages the priority which lets {@link TileServices} make decisions about which tiles
+ * to bind. Also holds on to and manages the {@link TileLifecycleManager}, informing it
+ * of when it is allowed to bind based on decisions frome the {@link TileServices}.
+ */
+public class TileServiceManager {
+
+ private static final long MIN_BIND_TIME = 5000;
+ private static final long UNBIND_DELAY = 30000;
+
+ public static final boolean DEBUG = true;
+
+ private static final String TAG = "TileServiceManager";
+
+ @VisibleForTesting
+ static final String PREFS_FILE = "CustomTileModes";
+
+ private final TileServices mServices;
+ private final TileLifecycleManager mStateManager;
+ private final Handler mHandler;
+ private boolean mBindRequested;
+ private boolean mBindAllowed;
+ private boolean mBound;
+ private int mPriority;
+ private boolean mJustBound;
+ private long mLastUpdate;
+ private int mType;
+
+ TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+ this(tileServices, handler, new TileLifecycleManager(handler,
+ tileServices.getContext(), new Intent().setComponent(component),
+ new UserHandle(ActivityManager.getCurrentUser())));
+ }
+
+ @VisibleForTesting
+ TileServiceManager(TileServices tileServices, Handler handler,
+ TileLifecycleManager tileLifecycleManager) {
+ mServices = tileServices;
+ mHandler = handler;
+ mStateManager = tileLifecycleManager;
+ mType = tileServices.getContext().getSharedPreferences(PREFS_FILE, 0)
+ .getInt(tileLifecycleManager.getComponent().flattenToString(),
+ TileService.TILE_MODE_UNSET);
+ mStateManager.setQSService(tileServices);
+ if (mType == TileService.TILE_MODE_UNSET) {
+ bindService();
+ mStateManager.onTileAdded();
+ }
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public void setType(int type) {
+ mServices.getContext().getSharedPreferences(PREFS_FILE, 0).edit()
+ .putInt(mStateManager.getComponent().flattenToString(), type).commit();
+ mType = type;
+ mServices.recalculateBindAllowance();
+ }
+
+ public IQSTileService getTileService() {
+ return mStateManager;
+ }
+
+ public void setBindRequested(boolean bindRequested) {
+ if (mBindRequested == bindRequested) return;
+ mBindRequested = bindRequested;
+ if (mBindAllowed && mBindRequested && !mBound) {
+ mHandler.removeCallbacks(mUnbind);
+ bindService();
+ } else {
+ mServices.recalculateBindAllowance();
+ }
+ if (mBound && !mBindRequested) {
+ mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+ }
+ }
+
+ public void setLastUpdate(long lastUpdate) {
+ mLastUpdate = lastUpdate;
+ if (mBound && mType == TileService.TILE_MODE_ACTIVE) {
+ mStateManager.onStopListening();
+ setBindRequested(false);
+ }
+ mServices.recalculateBindAllowance();
+ }
+
+ public void handleDestroy() {
+ mStateManager.handleDestroy();
+ }
+
+ public void setBindAllowed(boolean allowed) {
+ if (mBindAllowed == allowed) return;
+ mBindAllowed = allowed;
+ if (!mBindAllowed && mBound) {
+ unbindService();
+ } else if (mBindAllowed && mBindRequested && !mBound) {
+ bindService();
+ }
+ }
+
+ private void bindService() {
+ if (mBound) {
+ Log.e(TAG, "Service already bound");
+ return;
+ }
+ mBound = true;
+ mJustBound = true;
+ mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
+ mStateManager.setBindService(true);
+ }
+
+ private void unbindService() {
+ if (!mBound) {
+ Log.e(TAG, "Service not bound");
+ return;
+ }
+ mBound = false;
+ mJustBound = false;
+ mStateManager.setBindService(false);
+ }
+
+ public void calculateBindPriority(long currentTime) {
+ if (mStateManager.hasPendingClick()) {
+ // Pending click is the most important thing, need to put this service at the top of
+ // the list to be bound.
+ mPriority = Integer.MAX_VALUE;
+ } else if (mJustBound) {
+ // If we just bound, lets not thrash on binding/unbinding too much, this is second most
+ // important.
+ mPriority = Integer.MAX_VALUE - 1;
+ } else if (!mBindRequested) {
+ // Don't care about binding right now, put us last.
+ mPriority = Integer.MIN_VALUE;
+ } else {
+ // Order based on whether this was just updated.
+ long timeSinceUpdate = currentTime - mLastUpdate;
+ // Fit compare into integer space for simplicity. Make sure to leave MAX_VALUE and
+ // MAX_VALUE - 1 for the more important states above.
+ if (timeSinceUpdate > Integer.MAX_VALUE - 2) {
+ mPriority = Integer.MAX_VALUE - 2;
+ } else {
+ mPriority = (int) timeSinceUpdate;
+ }
+ }
+ }
+
+ public int getBindPriority() {
+ return mPriority;
+ }
+
+ private final Runnable mUnbind = new Runnable() {
+ @Override
+ public void run() {
+ if (mBound && !mBindRequested) {
+ unbindService();
+ }
+ }
+ };
+
+ @VisibleForTesting
+ final Runnable mJustBoundOver = new Runnable() {
+ @Override
+ public void run() {
+ mJustBound = false;
+ mServices.recalculateBindAllowance();
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
new file mode 100644
index 0000000..7403ae0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Runs the day-to-day operations of which tiles should be bound and when.
+ */
+public class TileServices extends IQSService.Stub {
+ static final int DEFAULT_MAX_BOUND = 3;
+ static final int REDUCED_MAX_BOUND = 1;
+
+ private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
+ private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+ private final Context mContext;
+ private final Handler mHandler;
+ private final QSTileHost mHost;
+
+ private int mMaxBound = DEFAULT_MAX_BOUND;
+
+ public TileServices(QSTileHost host, Looper looper) {
+ mHost = host;
+ mContext = mHost.getContext();
+ mContext.registerReceiver(mRequestListeningReceiver,
+ new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
+ mHandler = new Handler(looper);
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public TileServiceManager getTileWrapper(CustomTile tile) {
+ ComponentName component = tile.getComponent();
+ TileServiceManager service = onCreateTileService(component);
+ synchronized (mServices) {
+ mServices.put(tile, service);
+ mTiles.put(component, tile);
+ }
+ return service;
+ }
+
+ protected TileServiceManager onCreateTileService(ComponentName component) {
+ return new TileServiceManager(this, mHandler, component);
+ }
+
+ public void freeService(CustomTile tile, TileServiceManager service) {
+ synchronized (mServices) {
+ service.setBindAllowed(false);
+ mServices.remove(tile);
+ mTiles.remove(tile.getComponent());
+ }
+ }
+
+ public void setMemoryPressure(boolean memoryPressure) {
+ mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
+ recalculateBindAllowance();
+ }
+
+ public void recalculateBindAllowance() {
+ final ArrayList<TileServiceManager> services;
+ synchronized (mServices) {
+ services = new ArrayList<>(mServices.values());
+ }
+ final int N = services.size();
+ if (N > mMaxBound) {
+ long currentTime = System.currentTimeMillis();
+ // Precalculate the priority of services for binding.
+ for (int i = 0; i < N; i++) {
+ services.get(i).calculateBindPriority(currentTime);
+ }
+ // Sort them so we can bind the most important first.
+ Collections.sort(services, SERVICE_SORT);
+ }
+ int i;
+ // Allow mMaxBound items to bind.
+ for (i = 0; i < mMaxBound && i < N; i++) {
+ services.get(i).setBindAllowed(true);
+ }
+ // The rest aren't allowed to bind for now.
+ while (i < N) {
+ services.get(i).setBindAllowed(false);
+ i++;
+ }
+ }
+
+ private void verifyCaller(String packageName) {
+ try {
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+ Binder.getCallingUserHandle().getIdentifier());
+ if (Binder.getCallingUid() != uid) {
+ throw new SecurityException("Component outside caller's uid");
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new SecurityException(e);
+ }
+ }
+
+ private void requestListening(ComponentName component) {
+ synchronized (mServices) {
+ CustomTile customTile = getTileForComponent(component);
+ if (customTile == null) {
+ Log.d("TileServices", "Couldn't find tile for " + component);
+ return;
+ }
+ TileServiceManager service = mServices.get(customTile);
+ if (service.getType() != TileService.TILE_MODE_ACTIVE) {
+ return;
+ }
+ service.setBindRequested(true);
+ try {
+ service.getTileService().onStartListening();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public void setTileMode(ComponentName component, int mode) {
+ verifyCaller(component.getPackageName());
+ CustomTile customTile = getTileForComponent(component);
+ if (customTile != null) {
+ synchronized (mServices) {
+ mServices.get(customTile).setType(mode);
+ }
+ }
+ }
+
+ @Override
+ public void updateQsTile(Tile tile) {
+ verifyCaller(tile.getComponentName().getPackageName());
+ CustomTile customTile = getTileForComponent(tile.getComponentName());
+ if (customTile != null) {
+ synchronized (mServices) {
+ mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+ }
+ customTile.updateState(tile);
+ customTile.refreshState();
+ }
+ }
+
+ @Override
+ public void onShowDialog(Tile tile) {
+ verifyCaller(tile.getComponentName().getPackageName());
+ CustomTile customTile = getTileForComponent(tile.getComponentName());
+ if (customTile != null) {
+ customTile.onDialogShown();
+ mHost.collapsePanels();
+ }
+ }
+
+ private CustomTile getTileForComponent(ComponentName component) {
+ synchronized (mServices) {
+ return mTiles.get(component);
+ }
+ }
+
+ private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
+ requestListening(
+ (ComponentName) intent.getParcelableExtra(TileService.EXTRA_COMPONENT));
+ }
+ }
+ };
+
+ private static final Comparator<TileServiceManager> SERVICE_SORT =
+ new Comparator<TileServiceManager>() {
+ @Override
+ public int compare(TileServiceManager left, TileServiceManager right) {
+ return -Integer.compare(left.getBindPriority(), right.getBindPriority());
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index fc802dd..c696f88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -58,8 +58,6 @@
public void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
setEnabled(!mState.value);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
private void setEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index f73ee35..23a15b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,8 +71,6 @@
protected void handleClick() {
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
mSetting.setValue(mState.value ? 0 : 1);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index d96f735..4f9f46d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -107,8 +107,6 @@
Toast.LENGTH_LONG).show();
return;
}
- mDisable.setAllowAnimation(true);
- mDisableTotalSilence.setAllowAnimation(true);
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
if (mState.value) {
mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 12c1298..39d9da1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -64,7 +64,7 @@
}
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
boolean newState = !mState.value;
- refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+ refreshState(newState);
mFlashlightController.setFlashlight(newState);
}
@@ -73,8 +73,8 @@
// TODO: Flashlight available handling...
// state.visible = mFlashlightController.isAvailable();
state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
- if (arg instanceof UserBoolean) {
- boolean value = ((UserBoolean) arg).value;
+ if (arg instanceof Boolean) {
+ boolean value = (Boolean) arg;
if (value == state.value) {
return;
}
@@ -83,7 +83,6 @@
state.value = mFlashlightController.isEnabled();
}
final AnimationIcon icon = state.value ? mEnable : mDisable;
- icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
state.icon = icon;
int onOrOffId = state.value
? R.string.accessibility_quick_settings_flashlight_on
@@ -107,12 +106,12 @@
@Override
public void onFlashlightChanged(boolean enabled) {
- refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
+ refreshState(enabled);
}
@Override
public void onFlashlightError() {
- refreshState(UserBoolean.BACKGROUND_FALSE);
+ refreshState(false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 250d567..55aa32b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -59,8 +59,6 @@
final boolean isEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
mController.setHotspotEnabled(!isEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 08540f6..e79aabf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -67,8 +67,6 @@
mHost.openPanels();
MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
});
return;
@@ -76,8 +74,6 @@
final boolean wasEnabled = (Boolean) mState.value;
MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
mController.setLocationEnabled(!wasEnabled);
- mEnable.setAllowAnimation(true);
- mDisable.setAllowAnimation(true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d85cf60..7bce54b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -63,15 +63,14 @@
MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
final boolean newState = !mState.value;
mController.setRotationLocked(newState);
- refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+ refreshState(newState);
}
@Override
protected void handleUpdateState(BooleanState state, Object arg) {
if (mController == null) return;
- final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+ final boolean rotationLocked = arg != null ? (Boolean) arg
: mController.isRotationLocked();
- final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
// TODO: Handle accessibility rotation lock and whatnot.
// state.visible = mController.isRotationLockAffordanceVisible();
if (state.value == rotationLocked && state.contentDescription != null) {
@@ -80,18 +79,15 @@
}
state.value = rotationLocked;
final boolean portrait = isCurrentOrientationLockPortrait();
- final AnimationIcon icon;
if (rotationLocked) {
final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
: R.string.quick_settings_rotation_locked_landscape_label;
state.label = mContext.getString(label);
- icon = portrait ? mAutoToPortrait : mAutoToLandscape;
+ state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
} else {
state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
- icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
+ state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
}
- icon.setAllowAnimation(userInitiated);
- state.icon = icon;
state.contentDescription = getAccessibilityString(rotationLocked,
R.string.accessibility_rotation_lock_on_portrait,
R.string.accessibility_rotation_lock_on_landscape,
@@ -145,8 +141,7 @@
private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
@Override
public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
- refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
- : UserBoolean.BACKGROUND_FALSE);
+ refreshState(rotationLocked);
}
};
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 07915f8..255f29f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -93,12 +93,7 @@
}
private void refreshQuietModeState(boolean backgroundRefresh) {
- if (backgroundRefresh) {
- refreshState(isWorkModeEnabled() ? UserBoolean.BACKGROUND_TRUE
- : UserBoolean.BACKGROUND_FALSE);
- } else {
- refreshState(isWorkModeEnabled() ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
- }
+ refreshState(isWorkModeEnabled());
}
@Override
@@ -108,28 +103,22 @@
return;
}
- final boolean userInitialized;
- if (arg instanceof UserBoolean) {
- state.value = ((UserBoolean) arg).value;
- userInitialized = ((UserBoolean) arg).userInitiated;
+ if (arg instanceof Boolean) {
+ state.value = (Boolean) arg;
} else {
state.value = isWorkModeEnabled();
- userInitialized = false;
}
- final AnimationIcon icon;
state.label = mContext.getString(R.string.quick_settings_work_mode_label);
if (state.value) {
- icon = mEnable;
+ state.icon = mEnable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_work_mode_on);
} else {
- icon = mDisable;
+ state.icon = mDisable;
state.contentDescription = mContext.getString(
R.string.accessibility_quick_settings_work_mode_off);
}
- icon.setAllowAnimation(userInitialized);
- state.icon = icon;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index c08fb05..070b395 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -27,6 +27,7 @@
public static final int DismissSourceKeyboard = 0;
public static final int DismissSourceSwipeGesture = 1;
public static final int DismissSourceHeaderButton = 2;
+ public static final int DismissSourceHistorySwipeGesture = 3;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 384b86f..57074df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -51,12 +51,13 @@
import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
-import com.android.systemui.recents.events.ui.ResizeTaskEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -76,6 +77,7 @@
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
import com.android.systemui.recents.views.ViewAnimation;
+import com.android.systemui.statusbar.BaseStatusBar;
import java.util.ArrayList;
@@ -87,6 +89,9 @@
private final static String TAG = "RecentsActivity";
private final static boolean DEBUG = false;
+ private final static String KEY_SAVED_STATE_HISTORY_VISIBLE =
+ "saved_instance_state_history_visible";
+
public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
private RecentsPackageMonitor mPackageMonitor;
@@ -97,14 +102,9 @@
// Top level views
private RecentsView mRecentsView;
private SystemBarScrimViews mScrimViews;
- private ViewStub mEmptyViewStub;
- private View mEmptyView;
private ViewStub mHistoryViewStub;
private RecentsHistoryView mHistoryView;
- // Resize task debug
- private RecentsResizeTaskDialog mResizeTaskDebugDialog;
-
// Search AppWidget
private AppWidgetProviderInfo mSearchWidgetInfo;
private RecentsAppWidgetHost mAppWidgetHost;
@@ -197,7 +197,6 @@
loader.loadTasks(this, plan, loadOpts);
TaskStack stack = plan.getTaskStack();
- launchState.launchedWithNoRecentTasks = !plan.hasTasks();
mRecentsView.setTaskStack(stack);
// Mark the task that is the launch target
@@ -215,30 +214,13 @@
}
}
- // Update the top level view's visibilities
- if (launchState.launchedWithNoRecentTasks) {
- if (mEmptyView == null) {
- mEmptyView = mEmptyViewStub.inflate();
- }
- mEmptyView.setVisibility(View.VISIBLE);
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
- mRecentsView.setSearchBarVisibility(View.GONE);
- }
- } else {
- if (mEmptyView != null) {
- mEmptyView.setVisibility(View.GONE);
- }
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
- if (mRecentsView.hasValidSearchBar()) {
- mRecentsView.setSearchBarVisibility(View.VISIBLE);
- } else {
- refreshSearchWidgetView();
- }
- }
- }
-
// Animate the SystemUI scrims into view
- mScrimViews.prepareEnterRecentsAnimation();
+ boolean hasStatusBarScrim = stack.getStackTaskCount() > 0;
+ boolean animateStatusBarScrim = launchState.launchedFromHome;
+ boolean hasNavBarScrim = (stack.getStackTaskCount() > 0) && !config.hasTransposedNavBar;
+ boolean animateNavBarScrim = true;
+ mScrimViews.prepareEnterRecentsAnimation(hasStatusBarScrim, animateStatusBarScrim, hasNavBarScrim,
+ animateNavBarScrim);
// Keep track of whether we launched from the nav bar button or via alt-tab
if (launchState.launchedWithAltTab) {
@@ -317,12 +299,23 @@
*/
void dismissRecentsToHome(boolean animated) {
if (animated) {
- ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(this,
- null, mFinishLaunchHomeRunnable, null);
+ ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger();
+ exitTrigger.increment();
+ exitTrigger.addLastDecrementRunnable(mFinishLaunchHomeRunnable);
+ exitTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ }
+ });
mRecentsView.startExitToHomeAnimation(
new ViewAnimation.TaskViewExitContext(exitTrigger));
+ exitTrigger.decrement();
} else {
mFinishLaunchHomeRunnable.run();
+ Recents.getSystemServices().sendCloseSystemWindows(
+ BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
}
}
@@ -362,7 +355,7 @@
EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
// Initialize the widget host (the host id is static and does not change)
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
}
mPackageMonitor = new RecentsPackageMonitor();
@@ -374,7 +367,6 @@
mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
- mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
mHistoryViewStub = (ViewStub) findViewById(R.id.history_view_stub);
mScrimViews = new SystemBarScrimViews(this);
getWindow().getAttributes().privateFlags |=
@@ -388,14 +380,14 @@
mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
// Bind the search app widget when we first start up
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
}
// Register the broadcast receiver to handle messages when the screen is turned off
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
}
registerReceiver(mSystemBroadcastReceiver, filter);
@@ -495,7 +487,7 @@
mPackageMonitor.unregister();
// Stop listening for widget package changes if there was one bound
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
mAppWidgetHost.stopListening();
}
@@ -515,6 +507,21 @@
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE,
+ (mHistoryView != null) && mHistoryView.isVisible());
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ if (savedInstanceState.getBoolean(KEY_SAVED_STATE_HISTORY_VISIBLE, false)) {
+ EventBus.getDefault().send(new ShowHistoryEvent());
+ }
+ }
+
+ @Override
public void onTrimMemory(int level) {
RecentsTaskLoader loader = Recents.getTaskLoader();
if (loader != null) {
@@ -523,6 +530,22 @@
}
@Override
+ public void onMultiWindowModeChanged(boolean multiWindowMode) {
+ super.onMultiWindowModeChanged(multiWindowMode);
+ if (!multiWindowMode) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.loadIcons = false;
+ launchOpts.loadThumbnails = false;
+ launchOpts.onlyLoadForCache = true;
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
+ loader.preloadTasks(loadPlan, false);
+ loader.loadTasks(this, loadPlan, launchOpts);
+ EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack()));
+ }
+ }
+
+ @Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_TAB: {
@@ -580,15 +603,6 @@
EventBus.getDefault().send(new ToggleRecentsEvent());
}
- /**** RecentsResizeTaskDialog ****/
-
- private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
- if (mResizeTaskDebugDialog == null) {
- mResizeTaskDebugDialog = new RecentsResizeTaskDialog(getFragmentManager(), this);
- }
- return mResizeTaskDebugDialog;
- }
-
/**** EventBus events ****/
public final void onBusEvent(ToggleRecentsEvent event) {
@@ -603,16 +617,18 @@
}
public final void onBusEvent(IterateRecentsEvent event) {
- // Focus the next task
- EventBus.getDefault().send(new FocusNextTaskViewEvent());
+ if (!dismissHistory()) {
+ // Focus the next task
+ EventBus.getDefault().send(new FocusNextTaskViewEvent());
- // Start dozing after the recents button is clicked
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (debugFlags.isFastToggleRecentsEnabled()) {
- if (!mIterateTrigger.isDozing()) {
- mIterateTrigger.startDozing();
- } else {
- mIterateTrigger.poke();
+ // Start dozing after the recents button is clicked
+ RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+ if (debugFlags.isFastToggleRecentsEnabled()) {
+ if (!mIterateTrigger.isDozing()) {
+ mIterateTrigger.startDozing();
+ } else {
+ mIterateTrigger.poke();
+ }
}
}
}
@@ -630,16 +646,14 @@
} else if (event.triggeredFromHomeKey) {
// Otherwise, dismiss Recents to Home
if (mHistoryView != null && mHistoryView.isVisible()) {
- ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
- t.increment();
- t.addLastDecrementRunnable(new Runnable() {
+ HideHistoryEvent hideEvent = new HideHistoryEvent(true /* animate */);
+ hideEvent.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
dismissRecentsToHome(true /* animated */);
}
});
- EventBus.getDefault().send(new HideHistoryEvent(true, t));
- t.decrement();
+ EventBus.getDefault().send(hideEvent);
} else {
dismissRecentsToHome(true /* animated */);
@@ -651,11 +665,11 @@
public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
// Try and start the enter animation (or restart it on configuration changed)
- ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
+ ReferenceCountedTrigger t = new ReferenceCountedTrigger();
ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
ctx.postAnimationTrigger.increment();
- if (mSearchWidgetInfo != null) {
- if (!RecentsDebugFlags.Static.DisableSearchBar) {
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
+ if (mSearchWidgetInfo != null) {
ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
@Override
public void run() {
@@ -713,7 +727,7 @@
MetricsLogger.count(this, "overview_app_info", 1);
}
- public final void onBusEvent(DismissTaskViewEvent event) {
+ public final void onBusEvent(DismissTaskEvent event) {
// Remove any stored data from the loader
RecentsTaskLoader loader = Recents.getTaskLoader();
loader.deleteTaskData(event.task, false);
@@ -724,17 +738,18 @@
}
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
- // Just go straight home (no animation necessary because there are no more task views)
- dismissRecentsToHome(false /* animated */);
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.hasDockedTask()) {
+ mRecentsView.showEmptyView();
+ } else {
+ // Just go straight home (no animation necessary because there are no more task views)
+ dismissRecentsToHome(false /* animated */);
+ }
// Keep track of all-deletions
MetricsLogger.count(this, "overview_task_all_dismissed", 1);
}
- public final void onBusEvent(ResizeTaskEvent event) {
- getResizeTaskDebugDialog().showResizeTaskDialog(event.task, mRecentsView);
- }
-
public final void onBusEvent(LaunchTaskSucceededEvent event) {
MetricsLogger.histogram(this, "overview_task_launch_index", event.taskIndexFromStackFront);
}
@@ -769,13 +784,11 @@
// provided.
mHistoryView.setSystemInsets(mRecentsView.getSystemInsets());
}
- mHistoryView.show(mRecentsView.getTaskStack());
+ mHistoryView.show(mRecentsView.getTaskStack(), event.getAnimationTrigger());
}
public final void onBusEvent(HideHistoryEvent event) {
- if (mHistoryView != null) {
- mHistoryView.hide(event.animate, event.postAnimationTrigger);
- }
+ mHistoryView.hide(event.animate, event.getAnimationTrigger());
}
private void refreshSearchWidgetView() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index e0bd59b..4ab0740 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -28,7 +28,6 @@
public class RecentsActivityLaunchState {
public boolean launchedWithAltTab;
- public boolean launchedWithNoRecentTasks;
public boolean launchedFromAppWithThumbnail;
public boolean launchedFromHome;
public boolean launchedFromSearchHome;
@@ -49,67 +48,31 @@
launchedViaDragGesture = false;
}
- /** Returns whether the status bar scrim should be animated when shown for the first time. */
- public boolean shouldAnimateStatusBarScrim() {
- return true;
- }
-
- /** Returns whether the status bar scrim should be visible. */
- public boolean hasStatusBarScrim() {
- return !launchedWithNoRecentTasks;
- }
-
- /** Returns whether the nav bar scrim should be animated when shown for the first time. */
- public boolean shouldAnimateNavBarScrim() {
- return true;
- }
-
- /** Returns whether the nav bar scrim should be visible. */
- public boolean hasNavBarScrim() {
- // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
- RecentsConfiguration config = Recents.getConfiguration();
- return !launchedWithNoRecentTasks && !config.hasTransposedNavBar;
- }
-
/**
* Returns the task to focus given the current launch state.
*/
public int getInitialFocusTaskIndex(int numTasks) {
RecentsDebugFlags flags = Recents.getDebugFlags();
- if (flags.isPageOnToggleEnabled() && !launchedWithAltTab) {
- // If we are fast toggling, then focus the next task depending on when you are on home
- // or coming in from another app
+ if (launchedWithAltTab) {
+ if (launchedFromAppWithThumbnail) {
+ // If alt-tabbing from another app, focus the next task
+ return numTasks - 2;
+ } else {
+ // If alt-tabbing from home, focus the first task
+ return numTasks - 1;
+ }
+ } else {
if (launchedFromHome) {
return numTasks - 1;
} else {
if (flags.isFastToggleRecentsEnabled() || !flags.isInitialStatePaging()) {
+ // If we are not fast-toggling or are starting in the non-focused mode, then
+ // we should assume the front most task has focus
return numTasks - 1;
} else {
return numTasks - 2;
}
}
}
-
- if (launchedWithAltTab && launchedFromAppWithThumbnail) {
- // If alt-tabbing from another app, focus the next task
- return numTasks - 2;
- } else if ((launchedWithAltTab && launchedFromHome) ||
- (!launchedWithAltTab && launchedFromAppWithThumbnail)) {
- // If alt-tabbing from home, or launching from an app normally, focus that task
- return numTasks - 1;
- } else {
- // Otherwise, we are launching recents from home normally, focus no tasks so that we
- // know to return home
- return -1;
- }
- }
-
- @Override
- public String toString() {
- return "RecentsActivityLaunchState altTab: " + launchedWithAltTab +
- ", noTasks: " + launchedWithNoRecentTasks +
- ", fromHome: " + launchedFromHome +
- ", fromSearchHome: " + launchedFromSearchHome +
- ", reuse: " + launchedReuseTaskStackViews;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 53c10b7..cfbd1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -74,9 +74,6 @@
public int svelteLevel;
public int searchBarSpaceHeightPx;
- /** Dev options and global settings */
- public boolean lockToAppEnabled;
-
public RecentsConfiguration(Context context) {
// Load only resources that can not change after the first load either through developer
// settings or via multi window
@@ -106,12 +103,7 @@
/**
* Updates the configuration based on the current state of the system
*/
- void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
- // Only update resources that can change after the first load, either through developer
- // settings or via multi window
- lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
- ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
-
+ void update(Rect windowRect) {
// Recompute some values based on the given state, since we can not rely on the resource
// system to get certain values.
boolean isLandscape = windowRect.width() > windowRect.height();
@@ -143,16 +135,13 @@
int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
if (hasTransposedNavBar) {
// In landscape phones, the search bar appears on the left, but we overlay it on top
- int swInset = getInsetToSmallestWidth(windowBounds.right - rightInset -
- windowBounds.left);
- taskStackBounds.set(windowBounds.left + swInset, windowBounds.top + topInset,
- windowBounds.right - swInset - rightInset, windowBounds.bottom);
+ taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
+ windowBounds.right - rightInset, windowBounds.bottom);
} else {
// In portrait, the search bar appears on the top (which already has the inset)
- int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left);
int top = searchBarBounds.isEmpty() ? topInset : 0;
- taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom + top,
- windowBounds.right - swInset - rightInset, windowBounds.bottom);
+ taskStackBounds.set(windowBounds.left, searchBarBounds.bottom + top,
+ windowBounds.right - rightInset, windowBounds.bottom);
}
}
@@ -173,15 +162,4 @@
windowBounds.right, windowBounds.top + topInset + searchBarSize);
}
}
-
- /**
- * Constrain the width of the landscape stack to the smallest width of the device.
- */
- private int getInsetToSmallestWidth(int availableWidth) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (!debugFlags.isFullscreenThumbnailsEnabled() && (availableWidth > smallestWidth)) {
- return (availableWidth - smallestWidth) / 2;
- }
- return 0;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index d778886..c323522 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -26,17 +26,14 @@
*/
public class RecentsDebugFlags implements TunerService.Tunable {
- private static final String KEY_FAST_TOGGLE = "overview_fast_toggle";
- private static final String KEY_PAGE_ON_TOGGLE = "overview_page_on_toggle";
- private static final String KEY_FULLSCREEN_THUMBNAILS = "overview_fullscreen_thumbnails";
- private static final String KEY_SHOW_HISTORY = "overview_show_history";
+ private static final String KEY_FAST_TOGGLE = "overview_fast_toggle_via_button";
private static final String KEY_INITIAL_STATE_PAGING = "overview_initial_state_paging";
public static class Static {
// Enables debug drawing for the transition thumbnail
public static final boolean EnableTransitionThumbnailDebugMode = false;
- // This disables the search bar integration
- public static final boolean DisableSearchBar = true;
+ // This enables the search bar integration
+ public static final boolean EnableSearchBar = false;
// This disables the bitmap and icon caches
public static final boolean DisableBackgroundCache = false;
// Enables the simulated task affiliations
@@ -52,9 +49,6 @@
}
private boolean mFastToggleRecents;
- private boolean mPageOnToggle;
- private boolean mUseFullscreenThumbnails;
- private boolean mShowHistory;
private boolean mInitialStatePaging;
/**
@@ -64,36 +58,14 @@
public RecentsDebugFlags(Context context) {
// Register all our flags, this will also call onTuningChanged() for each key, which will
// initialize the current state of each flag
- TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_PAGE_ON_TOGGLE,
- KEY_FULLSCREEN_THUMBNAILS, KEY_SHOW_HISTORY, KEY_INITIAL_STATE_PAGING);
+ TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE, KEY_INITIAL_STATE_PAGING);
}
/**
* @return whether we are enabling fast toggling.
*/
public boolean isFastToggleRecentsEnabled() {
- return mPageOnToggle && mFastToggleRecents;
- }
-
- /**
- * @return whether the recents button toggles pages.
- */
- public boolean isPageOnToggleEnabled() {
- return mPageOnToggle;
- }
-
- /**
- * @return whether we should show fullscreen thumbnails
- */
- public boolean isFullscreenThumbnailsEnabled() {
- return mUseFullscreenThumbnails;
- }
-
- /**
- * @return whether we should show the history
- */
- public boolean isHistoryEnabled() {
- return mShowHistory;
+ return mFastToggleRecents;
}
/**
@@ -110,18 +82,6 @@
mFastToggleRecents = (newValue != null) &&
(Integer.parseInt(newValue) != 0);
break;
- case KEY_PAGE_ON_TOGGLE:
- mPageOnToggle = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
- break;
- case KEY_FULLSCREEN_THUMBNAILS:
- mUseFullscreenThumbnails = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
- break;
- case KEY_SHOW_HISTORY:
- mShowHistory = (newValue != null) &&
- (Integer.parseInt(newValue) != 0);
- break;
case KEY_INITIAL_STATE_PAGING:
mInitialStatePaging = (newValue != null) &&
(Integer.parseInt(newValue) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 2a4017a..fd00289 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ITaskStackListener;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
@@ -60,6 +61,7 @@
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
@@ -104,6 +106,10 @@
mHandler.post(this);
}
+ @Override
+ public void onActivityPinned() {
+ }
+
/** Preloads the next task */
public void run() {
// TODO: Temporarily skip this if multi stack is enabled
@@ -207,7 +213,7 @@
RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
loader.preloadTasks(plan, true /* isTopTaskHome */);
RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
- launchOpts.numVisibleTasks = loader.getApplicationIconCacheSize();
+ launchOpts.numVisibleTasks = loader.getIconCacheSize();
launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
launchOpts.onlyLoadForCache = true;
loader.loadTasks(mContext, plan, launchOpts);
@@ -333,7 +339,7 @@
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
RecentsDebugFlags flags = Recents.getDebugFlags();
- if (flags.isPageOnToggleEnabled() && !launchState.launchedWithAltTab) {
+ if (!launchState.launchedWithAltTab) {
// Notify recents to move onto the next task
EventBus.getDefault().post(new IterateRecentsEvent());
} else {
@@ -360,6 +366,9 @@
// Otherwise, start the recents activity
startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */);
+
+ // Only close the other system windows if we are actually showing recents
+ ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
mLastToggleTime = SystemClock.elapsedRealtime();
}
} catch (ActivityNotFoundException e) {
@@ -452,7 +461,7 @@
}
// Launch the task
- ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
+ ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
}
/**
@@ -524,7 +533,7 @@
MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
// Launch the task
- ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
+ ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.title, launchOpts);
}
public void showNextAffiliatedTask() {
@@ -572,9 +581,9 @@
Rect windowRect = ssp.getWindowRect();
// Update the configuration for the current state
- config.update(mContext, ssp, ssp.getWindowRect());
+ config.update(windowRect);
- if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
+ if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
// Try and pre-emptively bind the search widget on startup to ensure that we
// have the right thumbnail bounds to animate to.
// Note: We have to reload the widget id before we get the task stack bounds below
@@ -776,8 +785,10 @@
if (toTransform != null && toTask.key != null) {
Bitmap thumbnail;
synchronized (mHeaderBarLock) {
- int toHeaderWidth = (int) (mHeaderBar.getMeasuredWidth() * toTransform.scale);
+ int toHeaderWidth = (int) toTransform.rect.width();
int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale);
+ mHeaderBar.onTaskViewSizeChanged((int) toTransform.rect.width(),
+ (int) toTransform.rect.height());
thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight,
Bitmap.Config.ARGB_8888);
if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
@@ -848,11 +859,19 @@
if (!useThumbnailTransition) {
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition and do the animation from home
- if (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) {
+ if (hasRecentTasks) {
SystemServicesProxy ssp = Recents.getSystemServices();
String homeActivityPackage = ssp.getHomeActivityPackageName();
- String searchWidgetPackage = Prefs.getString(mContext,
- Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+ String searchWidgetPackage = null;
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
+ searchWidgetPackage = Prefs.getString(mContext,
+ Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+ } else {
+ AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
+ if (searchWidgetInfo != null) {
+ searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
+ }
+ }
// Determine whether we are coming from a search owned home activity
boolean fromSearchHome = (homeActivityPackage != null) &&
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
deleted file mode 100644
index d415845..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.recents;
-
-import android.app.ActivityManager;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.app.FragmentManager;
-import android.content.DialogInterface;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Button;
-import android.widget.Toast;
-import com.android.systemui.R;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.Task;
-import com.android.systemui.recents.views.RecentsView;
-
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-
-/**
- * A helper for the dialogs that show when task debugging is on.
- */
-public class RecentsResizeTaskDialog extends DialogFragment {
-
- static final String TAG = "RecentsResizeTaskDialog";
-
- // The various window arrangements we can handle.
- private static final int PLACE_LEFT = 1;
- private static final int PLACE_RIGHT = 2;
- private static final int PLACE_TOP = 3;
- private static final int PLACE_BOTTOM = 4;
- private static final int PLACE_TOP_LEFT = 5;
- private static final int PLACE_TOP_RIGHT = 6;
- private static final int PLACE_BOTTOM_LEFT = 7;
- private static final int PLACE_BOTTOM_RIGHT = 8;
- private static final int PLACE_FULL = 9;
- private static final int PLACE_DOCK_LEFT = 10;
- private static final int PLACE_DOCK_RIGHT = 11;
- private static final int PLACE_DOCK_TOP = 12;
- private static final int PLACE_DOCK_BOTTOM = 13;
-
- // The button resource ID combined with the arrangement command.
- private static final int[][] BUTTON_DEFINITIONS =
- {{R.id.place_dock_left, PLACE_DOCK_LEFT},
- {R.id.place_dock_right, PLACE_DOCK_RIGHT},
- {R.id.place_dock_top, PLACE_DOCK_TOP},
- {R.id.place_dock_bottom, PLACE_DOCK_BOTTOM},
- {R.id.place_left, PLACE_LEFT},
- {R.id.place_right, PLACE_RIGHT},
- {R.id.place_top, PLACE_TOP},
- {R.id.place_bottom, PLACE_BOTTOM},
- {R.id.place_top_left, PLACE_TOP_LEFT},
- {R.id.place_top_right, PLACE_TOP_RIGHT},
- {R.id.place_bottom_left, PLACE_BOTTOM_LEFT},
- {R.id.place_bottom_right, PLACE_BOTTOM_RIGHT},
- {R.id.place_full, PLACE_FULL}};
-
- // The task we want to resize.
- private FragmentManager mFragmentManager;
- private View mResizeTaskDialogContent;
- private RecentsActivity mRecentsActivity;
- private RecentsView mRecentsView;
- private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
- private Task[] mTasks = {null, null, null, null};
-
- /**
- * Called by FragmentManager
- */
- public RecentsResizeTaskDialog() {
- }
-
- public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
- mFragmentManager = mgr;
- mRecentsActivity = activity;
- }
-
- /** Shows the resize-task dialog. */
- void showResizeTaskDialog(Task mainTask, RecentsView rv) {
- mTasks[0] = mainTask;
- mRecentsView = rv;
- showAllowingStateLoss(mFragmentManager, TAG);
- }
-
- /** Creates a new resize-task dialog. */
- private void createResizeTaskDialog(LayoutInflater inflater, AlertDialog.Builder builder) {
- builder.setTitle(R.string.recents_caption_resize);
- mResizeTaskDialogContent =
- inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
-
- for (int i = 0; i < BUTTON_DEFINITIONS.length; i++) {
- Button b = (Button)mResizeTaskDialogContent.findViewById(BUTTON_DEFINITIONS[i][0]);
- if (b != null) {
- final int action = BUTTON_DEFINITIONS[i][1];
- b.setOnClickListener(
- new View.OnClickListener() {
- public void onClick(View v) {
- switch (action) {
- case PLACE_DOCK_LEFT:
- case PLACE_DOCK_RIGHT:
- case PLACE_DOCK_TOP:
- case PLACE_DOCK_BOTTOM:
- placeDockTasks(action);
- break;
- default:
- placeTasks(action);
- break;
- }
- }
- });
- }
- }
-
- builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dismissAllowingStateLoss();
- }
- });
-
- builder.setView(mResizeTaskDialogContent);
- }
-
- /** Helper function to place window(s) on the display according to an arrangement request. */
- private void placeTasks(int arrangement) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- Rect rect = ssp.getDisplayRect();
- for (int i = 0; i < mBounds.length; ++i) {
- mBounds[i].set(rect);
- if (i != 0) {
- mTasks[i] = null;
- }
- }
- int additionalTasks = 0;
- switch (arrangement) {
- case PLACE_LEFT:
- mBounds[0].right = mBounds[0].centerX();
- mBounds[1].left = mBounds[0].right;
- additionalTasks = 1;
- break;
- case PLACE_RIGHT:
- mBounds[1].right = mBounds[1].centerX();
- mBounds[0].left = mBounds[1].right;
- additionalTasks = 1;
- break;
- case PLACE_TOP:
- mBounds[0].bottom = mBounds[0].centerY();
- mBounds[1].top = mBounds[0].bottom;
- additionalTasks = 1;
- break;
- case PLACE_BOTTOM:
- mBounds[1].bottom = mBounds[1].centerY();
- mBounds[0].top = mBounds[1].bottom;
- additionalTasks = 1;
- break;
- case PLACE_TOP_LEFT: // TL, TR, BL, BR
- mBounds[0].right = mBounds[0].centerX();
- mBounds[0].bottom = mBounds[0].centerY();
- mBounds[1].left = mBounds[0].right;
- mBounds[1].bottom = mBounds[0].bottom;
- mBounds[2].right = mBounds[0].right;
- mBounds[2].top = mBounds[0].bottom;
- mBounds[3].left = mBounds[0].right;
- mBounds[3].top = mBounds[0].bottom;
- additionalTasks = 3;
- break;
- case PLACE_TOP_RIGHT: // TR, TL, BR, BL
- mBounds[0].left = mBounds[0].centerX();
- mBounds[0].bottom = mBounds[0].centerY();
- mBounds[1].right = mBounds[0].left;
- mBounds[1].bottom = mBounds[0].bottom;
- mBounds[2].left = mBounds[0].left;
- mBounds[2].top = mBounds[0].bottom;
- mBounds[3].right = mBounds[0].left;
- mBounds[3].top = mBounds[0].bottom;
- additionalTasks = 3;
- break;
- case PLACE_BOTTOM_LEFT: // BL, BR, TL, TR
- mBounds[0].right = mBounds[0].centerX();
- mBounds[0].top = mBounds[0].centerY();
- mBounds[1].left = mBounds[0].right;
- mBounds[1].top = mBounds[0].top;
- mBounds[2].right = mBounds[0].right;
- mBounds[2].bottom = mBounds[0].top;
- mBounds[3].left = mBounds[0].right;
- mBounds[3].bottom = mBounds[0].top;
- additionalTasks = 3;
- break;
- case PLACE_BOTTOM_RIGHT: // BR, BL, TR, TL
- mBounds[0].left = mBounds[0].centerX();
- mBounds[0].top = mBounds[0].centerY();
- mBounds[1].right = mBounds[0].left;
- mBounds[1].top = mBounds[0].top;
- mBounds[2].left = mBounds[0].left;
- mBounds[2].bottom = mBounds[0].top;
- mBounds[3].right = mBounds[0].left;
- mBounds[3].bottom = mBounds[0].top;
- additionalTasks = 3;
- break;
- case PLACE_FULL:
- // Nothing to change.
- mBounds[0] = new Rect();
- break;
- }
-
- // Get the other tasks.
- for (int i = 1; i <= additionalTasks && mTasks[i - 1] != null; ++i) {
- mTasks[i] = mRecentsView.getNextTaskOrTopTask(mTasks[i - 1]);
- // Do stop if we circled back to the first item.
- if (mTasks[i] == mTasks[0]) {
- mTasks[i] = null;
- }
- }
-
- // Get rid of the dialog.
- dismissAllowingStateLoss();
- mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
-
- // Show tasks as they might not be currently visible - beginning with the oldest so that
- // the focus ends on the selected one.
- for (int i = additionalTasks; i >= 0; --i) {
- if (mTasks[i] != null) {
- mRecentsView.launchTask(mTasks[i], mBounds[i], FREEFORM_WORKSPACE_STACK_ID);
- }
- }
- }
-
- /**
- * Helper function to place docked window(s) on the display according to an arrangement request.
- */
- private void placeDockTasks(int arrangement) {
- int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
- switch (arrangement) {
- case PLACE_DOCK_LEFT:
- createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
- break;
- case PLACE_DOCK_TOP:
- createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
- break;
- case PLACE_DOCK_RIGHT:
- createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
- break;
- case PLACE_DOCK_BOTTOM:
- createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
- break;
- }
-
- // Dismiss the dialog before trying to launch the task
- dismissAllowingStateLoss();
-
- if (mTasks[0].key.stackId != DOCKED_STACK_ID) {
- int taskId = mTasks[0].key.id;
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startTaskInDockedMode(taskId, createMode);
- mRecentsView.launchTask(mTasks[0], null, DOCKED_STACK_ID);
- } else {
- Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
- }
- }
-
- @Override
- public Dialog onCreateDialog(Bundle args) {
- LayoutInflater inflater = getActivity().getLayoutInflater();
- AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
- createResizeTaskDialog(inflater, builder);
- return builder.create();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index d72218f..5c49ac3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -28,6 +28,8 @@
import android.util.Log;
import android.util.MutableBoolean;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
@@ -220,6 +222,20 @@
// Only accessible from derived events
protected Event() {}
+ /**
+ * Called by the EventBus prior to dispatching this event to any subscriber of this event.
+ */
+ void onPreDispatch() {
+ // Do nothing
+ }
+
+ /**
+ * Called by the EventBus after dispatching this event to every subscriber of this event.
+ */
+ void onPostDispatch() {
+ // Do nothing
+ }
+
@Override
protected Object clone() throws CloneNotSupportedException {
Event evt = (Event) super.clone();
@@ -230,6 +246,51 @@
}
/**
+ * An event that represents an animated state change, which allows subscribers to coordinate
+ * callbacks which happen after the animation has taken place.
+ *
+ * Internally, it is guaranteed that increment() and decrement() will be called before and the
+ * after the event is dispatched.
+ */
+ public static class AnimatedEvent extends Event {
+
+ private final ReferenceCountedTrigger mTrigger = new ReferenceCountedTrigger();
+
+ // Only accessible from derived events
+ protected AnimatedEvent() {}
+
+ /**
+ * Returns the reference counted trigger that coordinates the animations for this event.
+ */
+ public ReferenceCountedTrigger getAnimationTrigger() {
+ return mTrigger;
+ }
+
+ /**
+ * Adds a callback that is guaranteed to be called after the state has changed regardless of
+ * whether an actual animation took place.
+ */
+ public void addPostAnimationCallback(Runnable r) {
+ mTrigger.addLastDecrementRunnable(r);
+ }
+
+ @Override
+ void onPreDispatch() {
+ mTrigger.increment();
+ }
+
+ @Override
+ void onPostDispatch() {
+ mTrigger.decrement();
+ }
+
+ @Override
+ protected Object clone() throws CloneNotSupportedException {
+ throw new CloneNotSupportedException();
+ }
+ }
+
+ /**
* An inter-process event super class that allows us to track user state across subscriber
* invocations.
*/
@@ -706,6 +767,11 @@
if (eventHandlers == null) {
return;
}
+
+ // Prepare this event
+ boolean hasPostedEvent = false;
+ event.onPreDispatch();
+
// We need to clone the list in case a subscriber unregisters itself during traversal
eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
for (final EventHandler eventHandler : eventHandlers) {
@@ -717,11 +783,24 @@
processEvent(eventHandler, event);
}
});
+ hasPostedEvent = true;
} else {
processEvent(eventHandler, event);
}
}
}
+
+ // Clean up after this event, deferring until all subscribers have been called
+ if (hasPostedEvent) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ event.onPostDispatch();
+ }
+ });
+ } else {
+ event.onPostDispatch();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
index 34c35a7..e85dea3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java
@@ -22,17 +22,11 @@
/**
* This is sent when the history view will be closed.
*/
-public class HideHistoryEvent extends EventBus.Event {
+public class HideHistoryEvent extends EventBus.AnimatedEvent {
public final boolean animate;
- public final ReferenceCountedTrigger postAnimationTrigger;
public HideHistoryEvent(boolean animate) {
- this(animate, null);
- }
-
- public HideHistoryEvent(boolean animate, ReferenceCountedTrigger postAnimationTrigger) {
this.animate = animate;
- this.postAnimationTrigger = postAnimationTrigger;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
new file mode 100644
index 0000000..457d81e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.recents.events.activity;
+
+import android.graphics.Rect;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.views.TaskView;
+
+/**
+ * This is sent to launch a task from Recents.
+ */
+public class LaunchTaskEvent extends EventBus.Event {
+
+ public final TaskView taskView;
+ public final Task task;
+ public final Rect targetTaskBounds;
+ public final int targetTaskStack;
+ public final boolean screenPinningRequested;
+
+ public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack,
+ boolean screenPinningRequested) {
+ this.taskView = taskView;
+ this.task = task;
+ this.targetTaskBounds = targetTaskBounds;
+ this.targetTaskStack = targetTaskStack;
+ this.screenPinningRequested = screenPinningRequested;
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
index 870119d..94e5a97 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java
@@ -17,10 +17,13 @@
package com.android.systemui.recents.events.activity;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
/**
* This is sent when the history view button is clicked.
*/
-public class ShowHistoryEvent extends EventBus.Event {
+public class ShowHistoryEvent extends EventBus.AnimatedEvent {
+
// Simple event
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
new file mode 100644
index 0000000..b94ed7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.recents.events.activity;
+
+import com.android.systemui.recents.RecentsAppWidgetHost;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.TaskStack;
+
+/**
+ * This is sent by the activity whenever the task stach has changed.
+ */
+public class TaskStackUpdatedEvent extends EventBus.Event {
+
+ /**
+ * A new TaskStack instance representing the latest stack state.
+ */
+ public final TaskStack stack;
+
+ public TaskStackUpdatedEvent(TaskStack stack) {
+ this.stack = stack;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
similarity index 80%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
index e0d83fd..bcbbde8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
@@ -18,15 +18,16 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.views.TaskView;
/**
- * This is sent when a {@link Task} is resized.
+ * This is sent when a {@link Task} has been dismissed.
*/
-public class ResizeTaskEvent extends EventBus.Event {
+public class DismissTaskEvent extends EventBus.Event {
public final Task task;
- public ResizeTaskEvent(Task task) {
+ public DismissTaskEvent(Task task) {
this.task = task;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
index 3deeb47..8aa4631 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java
@@ -25,18 +25,15 @@
/**
* This event is sent whenever a drag ends.
*/
-public class DragEndEvent extends EventBus.Event {
+public class DragEndEvent extends EventBus.AnimatedEvent {
public final Task task;
public final TaskView taskView;
public final DropTarget dropTarget;
- public final ReferenceCountedTrigger postAnimationTrigger;
- public DragEndEvent(Task task, TaskView taskView, DropTarget dropTarget,
- ReferenceCountedTrigger postAnimationTrigger) {
+ public DragEndEvent(Task task, TaskView taskView, DropTarget dropTarget) {
this.task = task;
this.taskView = taskView;
this.dropTarget = dropTarget;
- this.postAnimationTrigger = postAnimationTrigger;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 2eee1da..72ec7b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -20,14 +20,21 @@
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateFormat;
+import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
+import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
import java.util.Calendar;
@@ -49,28 +56,48 @@
static final int TASK_ROW_VIEW_TYPE = 1;
/**
- * View holder implementation.
+ * View holder implementation. The {@param TaskCallbacks} are only called for TaskRow view
+ * holders.
*/
- public static class ViewHolder extends RecyclerView.ViewHolder {
- public View mContent;
+ public static class ViewHolder extends RecyclerView.ViewHolder implements Task.TaskCallbacks {
+ public final View content;
public ViewHolder(View v) {
super(v);
- mContent = v;
+ content = v;
+ }
+
+ @Override
+ public void onTaskDataLoaded(Task task) {
+ // This callback is only made for TaskRow view holders
+ ImageView iv = (ImageView) content.findViewById(R.id.icon);
+ iv.setImageDrawable(task.icon);
+ }
+
+ @Override
+ public void onTaskDataUnloaded() {
+ // This callback is only made for TaskRow view holders
+ ImageView iv = (ImageView) content.findViewById(R.id.icon);
+ iv.setImageBitmap(null);
+ }
+
+ @Override
+ public void onTaskStackIdChanged() {
+ // Do nothing, this callback is only made for TaskRow view holders
}
}
/**
* A single row of content.
*/
- private interface Row {
+ interface Row {
int getViewType();
}
/**
* A date row.
*/
- private static class DateRow implements Row {
+ static class DateRow implements Row {
public final String date;
@@ -87,20 +114,20 @@
/**
* A task row.
*/
- private static class TaskRow implements Row, View.OnClickListener {
+ static class TaskRow implements Row, View.OnClickListener {
- public final String description;
- private final int mTaskId;
+ public final Task task;
+ public final int dateKey;
- public TaskRow(Task task) {
- mTaskId = task.key.id;
- description = task.activityLabel;
+ public TaskRow(Task task, int dateKey) {
+ this.task = task;
+ this.dateKey = dateKey;
}
@Override
public void onClick(View v) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(v.getContext(), mTaskId, description,
+ ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
ActivityOptions.makeBasic());
}
@@ -110,8 +137,12 @@
}
}
+ private Context mContext;
private LayoutInflater mLayoutInflater;
+ private final List<Task> mTasks = new ArrayList<>();
private final List<Row> mRows = new ArrayList<>();
+ private final SparseIntArray mTaskRowCount = new SparseIntArray();
+ private TaskStack mStack;
public RecentsHistoryAdapter(Context context) {
mLayoutInflater = LayoutInflater.from(context);
@@ -120,13 +151,17 @@
/**
* Updates this adapter with the given tasks.
*/
- public void updateTasks(Context context, List<Task> tasks) {
+ public void updateTasks(Context context, TaskStack stack) {
+ mContext = context;
+ mStack = stack;
+
final Locale l = context.getResources().getConfiguration().locale;
final String dateFormatStr = DateFormat.getBestDateTimePattern(l, "EEEEMMMMd");
- final List<Task> tasksMostRecent = new ArrayList<>(tasks);
+ final List<Task> tasksMostRecent = new ArrayList<>(stack.getHistoricalTasks());
Collections.reverse(tasksMostRecent);
- int prevDayKey = -1;
+ int prevDateKey = -1;
mRows.clear();
+ mTaskRowCount.clear();
for (Task task : tasksMostRecent) {
if (task.isFreeformTask()) {
continue;
@@ -134,16 +169,46 @@
Calendar cal = Calendar.getInstance(l);
cal.setTimeInMillis(task.key.lastActiveTime);
- int dayKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
- if (dayKey != prevDayKey) {
- prevDayKey = dayKey;
+ int dateKey = Objects.hash(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR));
+ if (dateKey != prevDateKey) {
+ prevDateKey = dateKey;
mRows.add(new DateRow(DateFormat.format(dateFormatStr, cal).toString()));
}
- mRows.add(new TaskRow(task));
+ mRows.add(new TaskRow(task, dateKey));
+ mTaskRowCount.put(dateKey, mTaskRowCount.get(dateKey, 0) + 1);
}
notifyDataSetChanged();
}
+ /**
+ * Removes historical tasks belonging to the specified package and user. We do not need to
+ * remove the task from the TaskStack since the TaskStackView will also receive this event.
+ */
+ public void removeTasks(String packageName, int userId) {
+ boolean packagesRemoved = false;
+ for (int i = mRows.size() - 1; i >= 0; i--) {
+ Row row = mRows.get(i);
+ if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
+ TaskRow taskRow = (TaskRow) row;
+ Task task = taskRow.task;
+ String taskPackage = task.key.getComponent().getPackageName();
+ if (task.key.userId == userId && taskPackage.equals(packageName)) {
+ i = removeTaskRow(i);
+ }
+ }
+ }
+ if (mRows.isEmpty()) {
+ dismissHistory();
+ }
+ }
+
+ /**
+ * Returns the row at the given {@param position}.
+ */
+ public Row getRow(int position) {
+ return mRows.get(position);
+ }
+
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
@@ -160,25 +225,55 @@
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+
Row row = mRows.get(position);
- int viewType = mRows.get(position).getViewType();
+ int viewType = row.getViewType();
switch (viewType) {
case DATE_ROW_VIEW_TYPE: {
- TextView tv = (TextView) holder.mContent;
+ TextView tv = (TextView) holder.content;
tv.setText(((DateRow) row).date);
break;
}
case TASK_ROW_VIEW_TYPE: {
- TextView tv = (TextView) holder.mContent;
TaskRow taskRow = (TaskRow) row;
- tv.setText(taskRow.description);
- tv.setOnClickListener(taskRow);
+ taskRow.task.addCallback(holder);
+ TextView tv = (TextView) holder.content.findViewById(R.id.description);
+ tv.setText(taskRow.task.title);
+ holder.content.setOnClickListener(taskRow);
+ loader.loadTaskData(taskRow.task);
break;
}
}
}
@Override
+ public void onViewRecycled(ViewHolder holder) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+
+ int position = holder.getAdapterPosition();
+ if (position != RecyclerView.NO_POSITION) {
+ Row row = mRows.get(position);
+ int viewType = row.getViewType();
+ if (viewType == TASK_ROW_VIEW_TYPE) {
+ TaskRow taskRow = (TaskRow) row;
+ taskRow.task.removeCallback(holder);
+ loader.unloadTaskData(taskRow.task);
+ }
+ }
+ }
+
+ public void onTaskRemoved(Task task, int position) {
+ // Since this is removed from the history, we need to update the stack as well to ensure
+ // that the model is correct
+ mStack.removeTask(task);
+ removeTaskRow(position);
+ if (mRows.isEmpty()) {
+ dismissHistory();
+ }
+ }
+
+ @Override
public int getItemCount() {
return mRows.size();
}
@@ -187,4 +282,37 @@
public int getItemViewType(int position) {
return mRows.get(position).getViewType();
}
+
+ /**
+ * Removes a task row, also removing the associated {@link DateRow} if there are no more tasks
+ * in that date group.
+ *
+ * @param position an adapter position of a task row such that 0 < position < num rows.
+ * @return the index of the last removed row
+ */
+ private int removeTaskRow(int position) {
+ // Remove the task at that row
+ TaskRow taskRow = (TaskRow) mRows.remove(position);
+ int numTasks = mTaskRowCount.get(taskRow.dateKey) - 1;
+ mTaskRowCount.put(taskRow.dateKey, numTasks);
+ notifyItemRemoved(position);
+
+ if (numTasks == 0) {
+ // If that was the last task row in the group, then remove the date as well
+ mRows.remove(position - 1);
+ mTaskRowCount.removeAt(mTaskRowCount.indexOfKey(taskRow.dateKey));
+ notifyItemRemoved(position - 1);
+ return position - 1;
+ } else {
+ return position;
+ }
+ }
+
+ /**
+ * Dismisses history back to the stack view.
+ */
+ private void dismissHistory() {
+ EventBus.getDefault().send(new HideHistoryEvent(true /* animate */));
+ EventBus.getDefault().send(new HideHistoryButtonEvent());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
new file mode 100644
index 0000000..e0a2730
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.recents.history;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
+
+
+/**
+ * An item touch handler for items in the history view.
+ */
+public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCallback {
+
+ private Context mContext;
+ private RecentsHistoryAdapter mAdapter;
+
+ public RecentsHistoryItemTouchCallbacks(Context context, RecentsHistoryAdapter adapter) {
+ super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
+ mContext = context;
+ mAdapter = adapter;
+ }
+
+ @Override
+ public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
+ RecyclerView.ViewHolder target) {
+ return false;
+ }
+
+ @Override
+ public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+ int viewType = mAdapter.getItemViewType(viewHolder.getAdapterPosition());
+ switch (viewType) {
+ case RecentsHistoryAdapter.DATE_ROW_VIEW_TYPE:
+ // Disallow swiping
+ return 0;
+ default:
+ return super.getSwipeDirs(recyclerView, viewHolder);
+ }
+ }
+
+ @Override
+ public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+ int position = viewHolder.getAdapterPosition();
+ if (position != RecyclerView.NO_POSITION) {
+ RecentsHistoryAdapter.Row row = mAdapter.getRow(position);
+ RecentsHistoryAdapter.TaskRow taskRow = (RecentsHistoryAdapter.TaskRow) row;
+
+ // Remove the task from the system
+ EventBus.getDefault().send(new DismissTaskEvent(taskRow.task));
+ mAdapter.onTaskRemoved(taskRow.task, position);
+
+ // Keep track of deletions by swiping within history
+ MetricsLogger.histogram(mContext, "overview_task_dismissed_source",
+ Constants.Metrics.DismissSourceHistorySwipeGesture);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
index 5851111..9524da5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java
@@ -21,6 +21,7 @@
import android.graphics.Rect;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowInsets;
@@ -29,8 +30,12 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.TaskStack;
/**
@@ -43,6 +48,7 @@
private RecyclerView mRecyclerView;
private RecentsHistoryAdapter mAdapter;
+ private RecentsHistoryItemTouchCallbacks mItemTouchHandler;
private boolean mIsVisible;
private Rect mSystemInsets = new Rect();
@@ -67,6 +73,7 @@
super(context, attrs, defStyleAttr, defStyleRes);
Resources res = context.getResources();
mAdapter = new RecentsHistoryAdapter(context);
+ mItemTouchHandler = new RecentsHistoryItemTouchCallbacks(context, mAdapter);
mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_slow_in);
@@ -77,17 +84,21 @@
/**
* Updates this history view with the recent tasks, and then shows it.
*/
- public void show(TaskStack stack) {
+ public void show(TaskStack stack, ReferenceCountedTrigger postHideAnimationTrigger) {
setVisibility(View.VISIBLE);
setAlpha(0f);
- animate()
- .alpha(1f)
- .setDuration(mHistoryTransitionDuration)
- .setInterpolator(mFastOutSlowInInterpolator)
- .withLayer()
- .start();
-
- mAdapter.updateTasks(getContext(), stack.computeAllTasksList());
+ postHideAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ animate()
+ .alpha(1f)
+ .setDuration(mHistoryTransitionDuration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .withLayer()
+ .start();
+ }
+ });
+ mAdapter.updateTasks(getContext(), stack);
mIsVisible = true;
}
@@ -142,6 +153,8 @@
mRecyclerView = (RecyclerView) findViewById(R.id.list);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+ ItemTouchHelper touchHelper = new ItemTouchHelper(mItemTouchHandler);
+ touchHelper.attachToRecyclerView(mRecyclerView);
}
@Override
@@ -165,8 +178,26 @@
}
@Override
+ protected void onAttachedToWindow() {
+ EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+ super.onAttachedToWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
setSystemInsets(insets.getSystemWindowInsets());
return insets;
}
+
+ /**** EventBus Events ****/
+
+ public final void onBusEvent(PackagesChangedEvent event) {
+ mAdapter.removeTasks(event.packageName, event.userId);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
index 401b448..367f2e2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java
@@ -29,9 +29,6 @@
*/
public class ReferenceCountedTrigger {
- private static final String TAG = "ReferenceCountedTrigger";
-
- Context mContext;
int mCount;
ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>();
ArrayList<Runnable> mLastDecRunnables = new ArrayList<Runnable>();
@@ -51,9 +48,12 @@
}
};
- public ReferenceCountedTrigger(Context context, Runnable firstIncRunnable,
- Runnable lastDecRunnable, Runnable errorRunanable) {
- mContext = context;
+ public ReferenceCountedTrigger() {
+ this(null, null, null);
+ }
+
+ public ReferenceCountedTrigger(Runnable firstIncRunnable, Runnable lastDecRunnable,
+ Runnable errorRunanable) {
if (firstIncRunnable != null) mFirstIncRunnables.add(firstIncRunnable);
if (lastDecRunnable != null) mLastDecRunnables.add(lastDecRunnable);
mErrorRunnable = errorRunanable;
@@ -77,31 +77,36 @@
/** Adds a runnable to the last-decrement runnables list. */
public void addLastDecrementRunnable(Runnable r) {
- // To ensure that the last decrement always calls, we increment and decrement after setting
- // the last decrement runnable
- boolean ensureLastDecrement = (mCount == 0);
- if (ensureLastDecrement) increment();
mLastDecRunnables.add(r);
- if (ensureLastDecrement) decrement();
}
/** Decrements the ref count */
public void decrement() {
mCount--;
- if (mCount == 0 && !mLastDecRunnables.isEmpty()) {
- int numRunnables = mLastDecRunnables.size();
- for (int i = 0; i < numRunnables; i++) {
- mLastDecRunnables.get(i).run();
- }
+ if (mCount == 0) {
+ flushLastDecrementRunnables();
} else if (mCount < 0) {
if (mErrorRunnable != null) {
mErrorRunnable.run();
} else {
- Log.e(TAG, "Invalid ref count");
+ throw new RuntimeException("Invalid ref count");
}
}
}
+ /**
+ * Runs and clears all the last-decrement runnables now.
+ */
+ public void flushLastDecrementRunnables() {
+ if (!mLastDecRunnables.isEmpty()) {
+ int numRunnables = mLastDecRunnables.size();
+ for (int i = 0; i < numRunnables; i++) {
+ mLastDecRunnables.get(i).run();
+ }
+ }
+ mLastDecRunnables.clear();
+ }
+
/** Convenience method to decrement this trigger as a runnable. */
public Runnable decrementAsRunnable() {
return mDecrementRunnable;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 8979843..108029d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -43,6 +43,7 @@
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -57,7 +58,7 @@
import android.util.MutableBoolean;
import android.util.Pair;
import android.view.Display;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -65,9 +66,9 @@
import com.android.internal.os.BackgroundThread;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.statusbar.BaseStatusBar;
import java.io.IOException;
import java.util.ArrayList;
@@ -79,6 +80,7 @@
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -127,8 +129,10 @@
mUm = UserManager.get(context);
mDisplay = mWm.getDefaultDisplay();
mRecentsPackage = context.getPackageName();
- mHasFreeformWorkspaceSupport = false &&
- mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ mHasFreeformWorkspaceSupport =
+ mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
+ Settings.Global.getInt(context.getContentResolver(),
+ DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
// Get the dummy thumbnail width/heights
Resources res = context.getResources();
@@ -194,6 +198,8 @@
int numTasksToQuery = Math.max(minNumTasksToQuery, numLatestTasks);
List<ActivityManager.RecentTaskInfo> tasks = mAm.getRecentTasksForUser(numTasksToQuery,
ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
+ ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS |
+ ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS |
ActivityManager.RECENT_IGNORE_UNAVAILABLE |
ActivityManager.RECENT_INCLUDE_PROFILES |
ActivityManager.RECENT_WITH_EXCLUDED, userId);
@@ -308,7 +314,8 @@
try {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setDockCreateMode(createMode);
- mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle());
+ options.setLaunchStackId(DOCKED_STACK_ID);
+ mIam.startActivityFromRecents(taskId, options.toBundle());
} catch (RemoteException e) {
e.printStackTrace();
}
@@ -496,6 +503,18 @@
}
/**
+ * Sends a message to close other system windows.
+ */
+ public void sendCloseSystemWindows(String reason) {
+ if (ActivityManagerNative.isSystemReady()) {
+ try {
+ ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ /**
* Returns the activity info for a given component name.
*
* @param cn The component name of the activity.
@@ -573,7 +592,7 @@
* Returns the activity icon for the ActivityInfo for a user, badging if
* necessary.
*/
- public Drawable getActivityIcon(ActivityInfo info, int userId) {
+ public Drawable getBadgedActivityIcon(ActivityInfo info, int userId) {
if (mPm == null) return null;
// If we are mocking, then return a mock label
@@ -586,9 +605,31 @@
}
/**
+ * Returns the task description icon, loading and badging it if it necessary.
+ */
+ public Drawable getBadgedTaskDescriptionIcon(ActivityManager.TaskDescription taskDescription,
+ int userId, Resources res) {
+
+ // If we are mocking, then return a mock label
+ if (RecentsDebugFlags.Static.EnableSystemServicesProxy) {
+ return new ColorDrawable(0xFF666666);
+ }
+
+ Bitmap tdIcon = taskDescription.getInMemoryIcon();
+ if (tdIcon == null) {
+ tdIcon = ActivityManager.TaskDescription.loadTaskDescriptionIcon(
+ taskDescription.getIconFilename(), userId);
+ }
+ if (tdIcon != null) {
+ return getBadgedIcon(new BitmapDrawable(res, tdIcon), userId);
+ }
+ return null;
+ }
+
+ /**
* Returns the given icon for a user, badging if necessary.
*/
- public Drawable getBadgedIcon(Drawable icon, int userId) {
+ private Drawable getBadgedIcon(Drawable icon, int userId) {
if (userId != UserHandle.myUserId()) {
icon = mPm.getUserBadgedIcon(icon, new UserHandle(userId));
}
@@ -598,7 +639,7 @@
/**
* Returns the given label for a user, badging if necessary.
*/
- public String getBadgedLabel(String label, int userId) {
+ private String getBadgedLabel(String label, int userId) {
if (userId != UserHandle.myUserId()) {
label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
}
@@ -610,7 +651,7 @@
if (mPm == null) return null;
if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return null;
- ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+ ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
if (defaultHomeActivity != null) {
return defaultHomeActivity.getPackageName();
@@ -698,7 +739,7 @@
/**
* Returns the first Recents widget from the same package as the global assist activity.
*/
- private AppWidgetProviderInfo resolveSearchAppWidget() {
+ public AppWidgetProviderInfo resolveSearchAppWidget() {
if (mAssistComponent == null) return null;
List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
@@ -812,8 +853,7 @@
ActivityOptions options) {
if (mIam != null) {
try {
- mIam.startActivityFromRecents(
- taskId, INVALID_STACK_ID, options == null ? null : options.toBundle());
+ mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
return true;
} catch (Exception e) {
Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
@@ -855,12 +895,11 @@
}
}
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) {
if (mWm == null) return;
try {
- WindowManagerGlobal.getWindowManagerService().registerDockDividerVisibilityListener(
- listener);
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 1845bf9..d6262ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -29,7 +29,6 @@
import com.android.systemui.Prefs;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.misc.SystemServicesProxy;
import java.util.ArrayList;
@@ -47,9 +46,6 @@
*/
public class RecentsTaskLoadPlan {
- private static String TAG = "RecentsTaskLoadPlan";
- private static boolean DEBUG = false;
-
private static int MIN_NUM_TASKS = 5;
private static int SESSION_BEGIN_TIME = 1000 /* ms/s */ * 60 /* s/min */ * 60 /* min/hr */ *
6 /* hrs */;
@@ -107,13 +103,6 @@
// Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(mRawTasks);
-
- if (DEBUG) {
- Log.d(TAG, "preloadRawTasks, tasks: " + mRawTasks.size());
- for (ActivityManager.RecentTaskInfo info : mRawTasks) {
- Log.d(TAG, " " + info.baseIntent + ", " + info.lastActiveTime);
- }
- }
}
/**
@@ -126,14 +115,10 @@
* - least-recent to most-recent freeform tasks
*/
public synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
- if (DEBUG) Log.d(TAG, "preloadPlan");
-
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsConfiguration config = Recents.getConfiguration();
SystemServicesProxy ssp = Recents.getSystemServices();
Resources res = mContext.getResources();
- ArrayList<Task> freeformTasks = new ArrayList<>();
- ArrayList<Task> stackTasks = new ArrayList<>();
+ ArrayList<Task> allTasks = new ArrayList<>();
if (mRawTasks == null) {
preloadRawTasks(isTopTaskHome);
}
@@ -151,58 +136,37 @@
// This task is only shown in the stack if it statisfies the historical time or min
// number of tasks constraints. Freeform tasks are also always shown.
- boolean isStackTask = true;
- if (debugFlags.isHistoryEnabled()) {
- boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
- isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
- (t.lastActiveTime >= lastStackActiveTime &&
- i >= (taskCount - MIN_NUM_TASKS)));
- if (isStackTask && newLastStackActiveTime < 0) {
- newLastStackActiveTime = t.lastActiveTime;
- }
+ boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
+ boolean isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
+ (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)));
+ if (isStackTask && newLastStackActiveTime < 0) {
+ newLastStackActiveTime = t.lastActiveTime;
}
- // Load the label, icon, and color
- String activityLabel = loader.getAndUpdateActivityLabel(taskKey, t.taskDescription,
- ssp);
- String contentDescription = loader.getAndUpdateContentDescription(taskKey,
- activityLabel, ssp, res);
- Drawable activityIcon = isStackTask
- ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, ssp, res, false)
+ // Load the title, icon, and color
+ String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
+ String contentDescription = loader.getAndUpdateContentDescription(taskKey, title, res);
+ Drawable icon = isStackTask
+ ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
: null;
+ Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
- Bitmap icon = t.taskDescription != null
- ? t.taskDescription.getInMemoryIcon() : null;
- String iconFilename = t.taskDescription != null
- ? t.taskDescription.getIconFilename() : null;
-
// Add the task to the stack
- Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel,
- contentDescription, activityIcon, activityColor, (i == (taskCount - 1)),
- config.lockToAppEnabled, !isStackTask, icon, iconFilename, t.bounds);
- task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, false);
- if (DEBUG) {
- Log.d(TAG, activityLabel + " bounds: " + t.bounds);
- }
+ Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
+ thumbnail, title, contentDescription, activityColor, !isStackTask,
+ t.bounds, t.taskDescription);
- if (task.isFreeformTask()) {
- freeformTasks.add(task);
- } else {
- stackTasks.add(task);
- }
+ allTasks.add(task);
}
- if (debugFlags.isHistoryEnabled() && newLastStackActiveTime != -1) {
+ if (newLastStackActiveTime != -1) {
Prefs.putLong(mContext, Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME,
newLastStackActiveTime);
}
// Initialize the stacks
- ArrayList<Task> allTasks = new ArrayList<>();
- allTasks.addAll(stackTasks);
- allTasks.addAll(freeformTasks);
mStack = new TaskStack();
- mStack.setTasks(allTasks);
+ mStack.setTasks(allTasks, false /* notifyStackChanges */);
mStack.createAffiliatedGroupings(mContext);
}
@@ -211,19 +175,13 @@
*/
public synchronized void executePlan(Options opts, RecentsTaskLoader loader,
TaskResourceLoadQueue loadQueue) {
- if (DEBUG) Log.d(TAG, "executePlan, # tasks: " + opts.numVisibleTasks +
- ", # thumbnails: " + opts.numVisibleTaskThumbnails +
- ", running task id: " + opts.runningTaskId);
-
RecentsConfiguration config = Recents.getConfiguration();
- SystemServicesProxy ssp = Recents.getSystemServices();
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
ArrayList<Task> tasks = mStack.getStackTasks();
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
- ActivityManager.RecentTaskInfo t = mRawTasks.get(i);
Task task = tasks.get(i);
Task.TaskKey taskKey = task.key;
@@ -237,17 +195,15 @@
}
if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
- if (task.activityIcon == null) {
- if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
- task.activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
- ssp, res, true);
+ if (task.icon == null) {
+ task.icon = loader.getAndUpdateActivityIcon(taskKey, task.taskDescription,
+ res, true);
}
}
if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
if (task.thumbnail == null || isRunningTask) {
- if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
if (config.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
- task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, true);
+ task.thumbnail = loader.getAndUpdateThumbnail(taskKey, true);
} else if (config.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
loadQueue.addTask(task);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 965e7a67..28338d83 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -93,23 +93,23 @@
Handler mMainThreadHandler;
TaskResourceLoadQueue mLoadQueue;
- TaskKeyLruCache<Drawable> mApplicationIconCache;
+ TaskKeyLruCache<Drawable> mIconCache;
TaskKeyLruCache<Bitmap> mThumbnailCache;
Bitmap mDefaultThumbnail;
- BitmapDrawable mDefaultApplicationIcon;
+ BitmapDrawable mDefaultIcon;
boolean mCancelled;
boolean mWaitingOnLoadQueue;
/** Constructor, creates a new loading thread that loads task resources in the background */
public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
- TaskKeyLruCache<Drawable> applicationIconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
- Bitmap defaultThumbnail, BitmapDrawable defaultApplicationIcon) {
+ TaskKeyLruCache<Drawable> iconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
+ Bitmap defaultThumbnail, BitmapDrawable defaultIcon) {
mLoadQueue = loadQueue;
- mApplicationIconCache = applicationIconCache;
+ mIconCache = iconCache;
mThumbnailCache = thumbnailCache;
mDefaultThumbnail = defaultThumbnail;
- mDefaultApplicationIcon = defaultApplicationIcon;
+ mDefaultIcon = defaultIcon;
mMainThreadHandler = new Handler();
mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
@@ -163,30 +163,30 @@
// Load the next item from the queue
final Task t = mLoadQueue.nextTask();
if (t != null) {
- Drawable cachedIcon = mApplicationIconCache.get(t.key);
+ Drawable cachedIcon = mIconCache.get(t.key);
Bitmap cachedThumbnail = mThumbnailCache.get(t.key);
- // Load the application icon if it is stale or we haven't cached one yet
+ // Load the icon if it is stale or we haven't cached one yet
if (cachedIcon == null) {
- cachedIcon = getTaskDescriptionIcon(t.key, t.icon, t.iconFilename, ssp,
- mContext.getResources());
+ cachedIcon = ssp.getBadgedTaskDescriptionIcon(t.taskDescription,
+ t.key.userId, mContext.getResources());
if (cachedIcon == null) {
ActivityInfo info = ssp.getActivityInfo(
t.key.getComponent(), t.key.userId);
if (info != null) {
if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
- cachedIcon = ssp.getActivityIcon(info, t.key.userId);
+ cachedIcon = ssp.getBadgedActivityIcon(info, t.key.userId);
}
}
if (cachedIcon == null) {
- cachedIcon = mDefaultApplicationIcon;
+ cachedIcon = mDefaultIcon;
}
// At this point, even if we can't load the icon, we will set the
// default icon.
- mApplicationIconCache.put(t.key, cachedIcon);
+ mIconCache.put(t.key, cachedIcon);
}
// Load the thumbnail if it is stale or we haven't cached one yet
if (cachedThumbnail == null) {
@@ -234,18 +234,6 @@
}
}
}
-
- Drawable getTaskDescriptionIcon(Task.TaskKey taskKey, Bitmap iconBitmap, String iconFilename,
- SystemServicesProxy ssp, Resources res) {
- Bitmap tdIcon = iconBitmap != null
- ? iconBitmap
- : ActivityManager.TaskDescription.loadTaskDescriptionIcon(iconFilename,
- taskKey.userId);
- if (tdIcon != null) {
- return ssp.getBadgedIcon(new BitmapDrawable(res, tdIcon), taskKey.userId);
- }
- return null;
- }
}
/**
@@ -262,7 +250,7 @@
// active time. Instead, we rely on the RecentsPackageMonitor to keep us informed whenever a
// package in the cache has been updated, so that we may remove it.
private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
- private final TaskKeyLruCache<Drawable> mApplicationIconCache;
+ private final TaskKeyLruCache<Drawable> mIconCache;
private final TaskKeyLruCache<Bitmap> mThumbnailCache;
private final TaskKeyLruCache<String> mActivityLabelCache;
private final TaskKeyLruCache<String> mContentDescriptionCache;
@@ -275,7 +263,7 @@
private int mNumVisibleThumbnailsLoaded;
int mDefaultTaskBarBackgroundColor;
- BitmapDrawable mDefaultApplicationIcon;
+ BitmapDrawable mDefaultIcon;
Bitmap mDefaultThumbnail;
public RecentsTaskLoader(Context context) {
@@ -295,22 +283,22 @@
mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
mDefaultThumbnail.setHasAlpha(false);
mDefaultThumbnail.eraseColor(0xFFffffff);
- mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
+ mDefaultIcon = new BitmapDrawable(context.getResources(), icon);
// Initialize the proxy, cache and loaders
int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
mLoadQueue = new TaskResourceLoadQueue();
- mApplicationIconCache = new TaskKeyLruCache<>(iconCacheSize);
+ mIconCache = new TaskKeyLruCache<>(iconCacheSize);
mThumbnailCache = new TaskKeyLruCache<>(thumbnailCacheSize);
mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks);
mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks);
mActivityInfoCache = new LruCache(numRecentTasks);
- mLoader = new BackgroundTaskLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
- mDefaultThumbnail, mDefaultApplicationIcon);
+ mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mThumbnailCache,
+ mDefaultThumbnail, mDefaultIcon);
}
/** Returns the size of the app icon cache. */
- public int getApplicationIconCacheSize() {
+ public int getIconCacheSize() {
return mMaxIconCacheSize;
}
@@ -348,33 +336,33 @@
/** Acquires the task resource data directly from the pool. */
public void loadTaskData(Task t) {
- Drawable applicationIcon = mApplicationIconCache.getAndInvalidateIfModified(t.key);
+ Drawable icon = mIconCache.getAndInvalidateIfModified(t.key);
Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(t.key);
// Grab the thumbnail/icon from the cache, if either don't exist, then trigger a reload and
// use the default assets in their place until they load
- boolean requiresLoad = (applicationIcon == null) || (thumbnail == null);
- applicationIcon = applicationIcon != null ? applicationIcon : mDefaultApplicationIcon;
+ boolean requiresLoad = (icon == null) || (thumbnail == null);
+ icon = icon != null ? icon : mDefaultIcon;
if (requiresLoad) {
mLoadQueue.addTask(t);
}
- t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, applicationIcon);
+ t.notifyTaskDataLoaded(thumbnail == mDefaultThumbnail ? null : thumbnail, icon);
}
/** Releases the task resource data back into the pool. */
public void unloadTaskData(Task t) {
mLoadQueue.removeTask(t);
- t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
+ t.notifyTaskDataUnloaded(null, mDefaultIcon);
}
/** Completely removes the resource data from the pool. */
public void deleteTaskData(Task t, boolean notifyTaskDataUnloaded) {
mLoadQueue.removeTask(t);
mThumbnailCache.remove(t.key);
- mApplicationIconCache.remove(t.key);
+ mIconCache.remove(t.key);
mActivityInfoCache.remove(t.key.getComponent());
if (notifyTaskDataUnloaded) {
- t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
+ t.notifyTaskDataUnloaded(null, mDefaultIcon);
}
}
@@ -396,14 +384,14 @@
} else if (config.svelteLevel >= RecentsConfiguration.SVELTE_DISABLE_CACHE) {
mThumbnailCache.evictAll();
}
- mApplicationIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
+ mIconCache.trimToSize(Math.max(mNumVisibleTasksLoaded,
mMaxIconCacheSize / 2));
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
// We are leaving recents, so trim the data a bit
mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 2));
- mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
+ mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
mActivityInfoCache.trimToSize(Math.max(1,
ActivityManager.getMaxRecentTasksStatic() / 2));
break;
@@ -411,7 +399,7 @@
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
// We are going to be low on memory
mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 4));
- mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
+ mIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
mActivityInfoCache.trimToSize(Math.max(1,
ActivityManager.getMaxRecentTasksStatic() / 4));
break;
@@ -419,7 +407,7 @@
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
// We are low on memory, so release everything
mThumbnailCache.evictAll();
- mApplicationIconCache.evictAll();
+ mIconCache.evictAll();
mActivityInfoCache.evictAll();
// The cache is small, only clear the label cache when we are critical
mActivityLabelCache.evictAll();
@@ -433,8 +421,9 @@
/**
* Returns the cached task label if the task key is not expired, updating the cache if it is.
*/
- String getAndUpdateActivityLabel(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
- SystemServicesProxy ssp) {
+ String getAndUpdateActivityTitle(Task.TaskKey taskKey, ActivityManager.TaskDescription td) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+
// Return the task description label if it exists
if (td != null && td.getLabel() != null) {
return td.getLabel();
@@ -445,7 +434,7 @@
return label;
}
// All short paths failed, load the label from the activity info and cache it
- ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+ ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
label = ssp.getActivityLabel(activityInfo);
mActivityLabelCache.put(taskKey, label);
@@ -461,7 +450,9 @@
* cache if it is.
*/
String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
- SystemServicesProxy ssp, Resources res) {
+ Resources res) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+
// Return the cached content description if it exists
String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
if (label != null) {
@@ -486,28 +477,29 @@
* Returns the cached task icon if the task key is not expired, updating the cache if it is.
*/
Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
- SystemServicesProxy ssp, Resources res, boolean loadIfNotCached) {
+ Resources res, boolean loadIfNotCached) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+
// Return the cached activity icon if it exists
- Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
+ Drawable icon = mIconCache.getAndInvalidateIfModified(taskKey);
if (icon != null) {
return icon;
}
if (loadIfNotCached) {
// Return and cache the task description icon if it exists
- icon = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
- td.getIconFilename(), ssp, res);
+ icon = ssp.getBadgedTaskDescriptionIcon(td, taskKey.userId, res);
if (icon != null) {
- mApplicationIconCache.put(taskKey, icon);
+ mIconCache.put(taskKey, icon);
return icon;
}
// Load the icon from the activity info and cache it
- ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+ ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey);
if (activityInfo != null) {
- icon = ssp.getActivityIcon(activityInfo, taskKey.userId);
+ icon = ssp.getBadgedActivityIcon(activityInfo, taskKey.userId);
if (icon != null) {
- mApplicationIconCache.put(taskKey, icon);
+ mIconCache.put(taskKey, icon);
return icon;
}
}
@@ -519,8 +511,9 @@
/**
* Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
*/
- Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, SystemServicesProxy ssp,
- boolean loadIfNotCached) {
+ Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+
// Return the cached thumbnail if it exists
Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
if (thumbnail != null) {
@@ -543,7 +536,8 @@
}
/**
- * Returns the task's primary color.
+ * Returns the task's primary color if possible, defaulting to the default color if there is
+ * no specified primary color.
*/
int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
if (td != null && td.getPrimaryColor() != 0) {
@@ -556,7 +550,8 @@
* Returns the activity info for the given task key, retrieving one from the system if the
* task key is expired.
*/
- private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey, SystemServicesProxy ssp) {
+ private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
ComponentName cn = taskKey.getComponent();
ActivityInfo activityInfo = mActivityInfoCache.get(cn);
if (activityInfo == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 512effa..d030fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents.model;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -26,6 +27,7 @@
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
+import java.util.ArrayList;
import java.util.Objects;
@@ -36,10 +38,9 @@
/* Task callbacks */
public interface TaskCallbacks {
/* Notifies when a task has been bound */
- public void onTaskDataLoaded();
+ public void onTaskDataLoaded(Task task);
/* Notifies when a task has been unbound */
public void onTaskDataUnloaded();
-
/* Notifies when a task's stack id has changed. */
public void onTaskStackIdChanged();
}
@@ -92,82 +93,107 @@
}
public TaskKey key;
+
+ /**
+ * The group will be computed separately from the initialization of the task
+ */
public TaskGrouping group;
- // The taskAffiliationId is the task id of the parent task or itself if it is not affiliated with any task
- public int taskAffiliationId;
- public int taskAffiliationColor;
- public boolean isLaunchTarget;
- public Drawable applicationIcon;
- public Drawable activityIcon;
+ /**
+ * The affiliationTaskId is the task id of the parent task or itself if it is not affiliated
+ * with any task.
+ */
+ public int affiliationTaskId;
+ public int affiliationColor;
+
+ /**
+ * The icon is the task description icon (if provided), which falls back to the activity icon,
+ * which can then fall back to the application icon.
+ */
+ public Drawable icon;
+ public Bitmap thumbnail;
+ public String title;
public String contentDescription;
- public String activityLabel;
public int colorPrimary;
public boolean useLightOnPrimaryColor;
- public Bitmap thumbnail;
- public boolean lockToThisTask;
- public boolean lockToTaskEnabled;
- public boolean isHistorical;
- public Bitmap icon;
- public String iconFilename;
+
+ /**
+ * The bounds of the task, used only if it is a freeform task.
+ */
public Rect bounds;
- private TaskCallbacks mCb;
+ /**
+ * The task description for this task, only used to reload task icons.
+ */
+ public ActivityManager.TaskDescription taskDescription;
+
+ /**
+ * The state isLaunchTarget will be set for the correct task upon launching Recents.
+ */
+ public boolean isLaunchTarget;
+ public boolean isHistorical;
+
+ private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
public Task() {
// Do nothing
}
- public Task(TaskKey key, int taskAffiliation, int taskAffiliationColor,
- String activityTitle, String contentDescription, Drawable activityIcon,
- int colorPrimary, boolean lockToThisTask, boolean lockToTaskEnabled,
- boolean isHistorical, Bitmap icon, String iconFilename, Rect bounds) {
- boolean isInAffiliationGroup = (taskAffiliation != key.id);
- boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
+ public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
+ Bitmap thumbnail, String title, String contentDescription, int colorPrimary,
+ boolean isHistorical, Rect bounds,
+ ActivityManager.TaskDescription taskDescription) {
+ boolean isInAffiliationGroup = (affiliationTaskId != key.id);
+ boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
this.key = key;
- this.taskAffiliationId = taskAffiliation;
- this.taskAffiliationColor = taskAffiliationColor;
- this.activityLabel = activityTitle;
+ this.affiliationTaskId = affiliationTaskId;
+ this.affiliationColor = affiliationColor;
+ this.icon = icon;
+ this.thumbnail = thumbnail;
+ this.title = title;
this.contentDescription = contentDescription;
- this.activityIcon = activityIcon;
- this.colorPrimary = hasAffiliationGroupColor ? taskAffiliationColor : colorPrimary;
+ this.colorPrimary = hasAffiliationGroupColor ? affiliationColor : colorPrimary;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
Color.WHITE) > 3f;
- this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
- this.lockToTaskEnabled = lockToTaskEnabled;
- this.isHistorical = isHistorical;
- this.icon = icon;
- this.iconFilename = iconFilename;
this.bounds = bounds;
+ this.taskDescription = taskDescription;
+ this.isHistorical = isHistorical;
}
/** Copies the other task. */
public void copyFrom(Task o) {
this.key = o.key;
- this.taskAffiliationId = o.taskAffiliationId;
- this.taskAffiliationColor = o.taskAffiliationColor;
- this.activityLabel = o.activityLabel;
+ this.group = o.group;
+ this.affiliationTaskId = o.affiliationTaskId;
+ this.affiliationColor = o.affiliationColor;
+ this.icon = o.icon;
+ this.thumbnail = o.thumbnail;
+ this.title = o.title;
this.contentDescription = o.contentDescription;
- this.activityIcon = o.activityIcon;
this.colorPrimary = o.colorPrimary;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
- this.lockToThisTask = o.lockToThisTask;
- this.lockToTaskEnabled = o.lockToTaskEnabled;
- this.isHistorical = o.isHistorical;
- this.icon = o.icon;
- this.iconFilename = o.iconFilename;
this.bounds = o.bounds;
+ this.isLaunchTarget = o.isLaunchTarget;
+ this.isHistorical = o.isHistorical;
}
- /** Set the callbacks */
- public void setCallbacks(TaskCallbacks cb) {
- mCb = cb;
+ /**
+ * Add a callback.
+ */
+ public void addCallback(TaskCallbacks cb) {
+ if (!mCallbacks.contains(cb)) {
+ mCallbacks.add(cb);
+ }
+ }
+
+ /**
+ * Remove a callback.
+ */
+ public void removeCallback(TaskCallbacks cb) {
+ mCallbacks.remove(cb);
}
/** Set the grouping */
public void setGroup(TaskGrouping group) {
- if (group != null && this.group != null) {
- throw new RuntimeException("This task is already assigned to a group.");
- }
this.group = group;
}
@@ -176,8 +202,9 @@
*/
public void setStackId(int stackId) {
key.stackId = stackId;
- if (mCb != null) {
- mCb.onTaskStackIdChanged();
+ int callbackCount = mCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ mCallbacks.get(i).onTaskStackIdChanged();
}
}
@@ -191,19 +218,21 @@
/** Notifies the callback listeners that this task has been loaded */
public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
- this.applicationIcon = applicationIcon;
+ this.icon = applicationIcon;
this.thumbnail = thumbnail;
- if (mCb != null) {
- mCb.onTaskDataLoaded();
+ int callbackCount = mCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ mCallbacks.get(i).onTaskDataLoaded(this);
}
}
/** Notifies the callback listeners that this task has been unloaded */
public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultApplicationIcon) {
- applicationIcon = defaultApplicationIcon;
+ icon = defaultApplicationIcon;
thumbnail = defaultThumbnail;
- if (mCb != null) {
- mCb.onTaskDataUnloaded();
+ int callbackCount = mCallbacks.size();
+ for (int i = 0; i < callbackCount; i++) {
+ mCallbacks.get(i).onTaskDataUnloaded();
}
}
@@ -211,7 +240,7 @@
* Returns whether this task is affiliated with another task.
*/
public boolean isAffiliatedTask() {
- return key.id != taskAffiliationId;
+ return key.id != affiliationTaskId;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 13ab392..5e720cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -206,11 +206,20 @@
/** Task stack callbacks */
public interface TaskStackCallbacks {
- /* Notifies when a task has been removed from the stack */
+ /**
+ * Notifies when a new task has been added to the stack.
+ */
+ void onStackTaskAdded(TaskStack stack, Task newTask);
+
+ /**
+ * Notifies when a task has been removed from the stack.
+ */
void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
Task newFrontMostTask);
- /* Notifies when a task has been removed from the history */
+ /**
+ * Notifies when a task has been removed from the history.
+ */
void onHistoryTaskRemoved(TaskStack stack, Task removedTask);
}
@@ -223,16 +232,16 @@
public static final DockState NONE = new DockState(-1, 96, null, null);
public static final DockState LEFT = new DockState(
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
- new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.25f, 1));
+ new RectF(0, 0, 0.15f, 1), new RectF(0, 0, 0.15f, 1));
public static final DockState TOP = new DockState(
DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
- new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.25f));
+ new RectF(0, 0, 1, 0.15f), new RectF(0, 0, 1, 0.15f));
public static final DockState RIGHT = new DockState(
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
- new RectF(0.75f, 0, 1, 1), new RectF(0.75f, 0, 1, 1));
+ new RectF(0.85f, 0, 1, 1), new RectF(0.85f, 0, 1, 1));
public static final DockState BOTTOM = new DockState(
DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
- new RectF(0, 0.75f, 1, 1), new RectF(0, 0.75f, 1, 1));
+ new RectF(0, 0.85f, 1, 1), new RectF(0, 0.85f, 1, 1));
@Override
public boolean acceptsDrop(int x, int y, int width, int height) {
@@ -312,9 +321,24 @@
}
};
+ // A comparator that sorts tasks by their last active time and freeform state
+ private Comparator<Task> FREEFORM_LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
+ @Override
+ public int compare(Task o1, Task o2) {
+ if (o1.isFreeformTask() && !o2.isFreeformTask()) {
+ return 1;
+ } else if (o2.isFreeformTask() && !o1.isFreeformTask()) {
+ return -1;
+ }
+ return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
+ }
+ };
+
+
// The task offset to apply to a task id as a group affiliation
static final int IndividualTaskIdOffset = 1 << 16;
+ ArrayList<Task> mRawTaskList = new ArrayList<>();
FilteredTaskList mStackTaskList = new FilteredTaskList();
FilteredTaskList mHistoryTaskList = new FilteredTaskList();
TaskStackCallbacks mCb;
@@ -328,28 +352,28 @@
@Override
public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
if (t.isAffiliatedTask()) {
- // If this task is affiliated with another parent in the stack, then the historical state of this
- // task depends on the state of the parent task
- Task parentTask = taskIdMap.get(t.taskAffiliationId);
+ // If this task is affiliated with another parent in the stack, then the
+ // historical state of this task depends on the state of the parent task
+ Task parentTask = taskIdMap.get(t.affiliationTaskId);
if (parentTask != null) {
t = parentTask;
}
}
- return !t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
+ return !t.isHistorical;
}
});
mHistoryTaskList.setFilter(new TaskFilter() {
@Override
public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
if (t.isAffiliatedTask()) {
- // If this task is affiliated with another parent in the stack, then the historical state of this
- // task depends on the state of the parent task
- Task parentTask = taskIdMap.get(t.taskAffiliationId);
+ // If this task is affiliated with another parent in the stack, then the
+ // historical state of this task depends on the state of the parent task
+ Task parentTask = taskIdMap.get(t.affiliationTaskId);
if (parentTask != null) {
t = parentTask;
}
}
- return t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
+ return t.isHistorical;
}
});
}
@@ -397,24 +421,20 @@
taskList.remove(t);
// Remove it from the group as well, and if it is empty, remove the group
TaskGrouping group = t.group;
- group.removeTask(t);
- if (group.getTaskCount() == 0) {
- removeGroup(group);
+ if (group != null) {
+ group.removeTask(t);
+ if (group.getTaskCount() == 0) {
+ removeGroup(group);
+ }
}
- // Update the lock-to-app state
- t.lockToThisTask = false;
}
/** Removes a task */
public void removeTask(Task t) {
if (mStackTaskList.contains(t)) {
boolean wasFrontMostTask = (getStackFrontMostTask() == t);
- int removedTaskIndex = indexOfStackTask(t);
removeTaskImpl(mStackTaskList, t);
Task newFrontMostTask = getStackFrontMostTask();
- if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
- newFrontMostTask.lockToThisTask = true;
- }
if (mCb != null) {
// Notify that a task has been removed
mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
@@ -430,25 +450,90 @@
/**
* Sets a few tasks in one go, without calling any callbacks.
+ *
+ * @param tasks the new set of tasks to replace the current set.
+ * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
*/
- public void setTasks(List<Task> tasks) {
+ public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+ // Compute a has set for each of the tasks
+ HashMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
+ HashMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
+
+ ArrayList<Task> newTasks = new ArrayList<>();
+
+ // Disable notifications if there are no callbacks
+ if (mCb == null) {
+ notifyStackChanges = false;
+ }
+
+ // Remove any tasks that no longer exist
+ int taskCount = mRawTaskList.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = mRawTaskList.get(i);
+ if (!newTasksMap.containsKey(task.key)) {
+ if (notifyStackChanges) {
+ mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null);
+ }
+ }
+ task.setGroup(null);
+ }
+
+ // Add any new tasks
+ taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ if (!currentTasksMap.containsKey(task.key)) {
+ if (notifyStackChanges) {
+ mCb.onStackTaskAdded(this, task);
+ }
+ newTasks.add(task);
+ } else {
+ newTasks.add(currentTasksMap.get(task.key));
+ }
+ }
+
+ // Sort all the tasks to ensure they are ordered correctly
+ Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+
+ // TODO: Update screen pinning for the new front-most task post refactoring lockToTask out
+ // of the Task
+
+ // Filter out the historical tasks from this new list
ArrayList<Task> stackTasks = new ArrayList<>();
ArrayList<Task> historyTasks = new ArrayList<>();
- for (Task task : tasks) {
+ int newTaskCount = newTasks.size();
+ for (int i = 0; i < newTaskCount; i++) {
+ Task task = newTasks.get(i);
if (task.isHistorical) {
historyTasks.add(task);
} else {
stackTasks.add(task);
}
}
+
mStackTaskList.set(stackTasks);
mHistoryTaskList.set(historyTasks);
+ mRawTaskList.clear();
+ mRawTaskList.addAll(newTasks);
+ mGroups.clear();
+ mAffinitiesGroups.clear();
}
- /** Gets the front task */
+ /**
+ * Gets the front-most task in the stack.
+ */
public Task getStackFrontMostTask() {
- if (mStackTaskList.size() == 0) return null;
- return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
+ ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+ if (stackTasks.isEmpty()) {
+ return null;
+ }
+ for (int i = stackTasks.size() - 1; i >= 0; i--) {
+ Task task = stackTasks.get(i);
+ if (!task.isFreeformTask()) {
+ return task;
+ }
+ }
+ return null;
}
/** Gets the task keys */
@@ -572,7 +657,7 @@
Collections.sort(tasks, new Comparator<Task>() {
@Override
public int compare(Task task, Task task2) {
- return (int) (task.key.firstActiveTime - task2.key.firstActiveTime);
+ return Long.compare(task.key.firstActiveTime, task2.key.firstActiveTime);
}
});
// Create groups when sequential packages are the same
@@ -605,7 +690,7 @@
Collections.sort(mGroups, new Comparator<TaskGrouping>() {
@Override
public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
- return (int) (taskGrouping.latestActiveTimeInGroup -
+ return Long.compare(taskGrouping.latestActiveTimeInGroup,
taskGrouping2.latestActiveTimeInGroup);
}
});
@@ -618,7 +703,7 @@
Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
@Override
public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
- return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
+ return Long.compare(taskKey.firstActiveTime, taskKey2.firstActiveTime);
}
});
ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
@@ -637,7 +722,7 @@
for (int i = 0; i < taskCount; i++) {
Task t = tasks.get(i);
TaskGrouping group;
- int affiliation = t.taskAffiliationId > 0 ? t.taskAffiliationId :
+ int affiliation = t.affiliationTaskId > 0 ? t.affiliationTaskId :
IndividualTaskIdOffset + t.key.id;
if (mAffinitiesGroups.containsKey(affiliation)) {
group = getGroupWithAffiliation(affiliation);
@@ -658,7 +743,7 @@
// Ignore the groups that only have one task
if (taskCount <= 1) continue;
// Calculate the group color distribution
- int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
+ int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).affiliationColor;
float alphaStep = (1f - minAlpha) / taskCount;
float alpha = 1f;
for (int j = 0; j < taskCount; j++) {
@@ -714,4 +799,17 @@
}
return str;
}
-}
\ No newline at end of file
+
+ /**
+ * Given a list of tasks, returns a map of each task's key to the task.
+ */
+ private HashMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
+ HashMap<Task.TaskKey, Task> map = new HashMap<>();
+ int taskCount = tasks.size();
+ for (int i = 0; i < taskCount; i++) {
+ Task task = tasks.get(i);
+ map.put(task.key, task);
+ }
+ return map;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index f646a92..c0b8a9d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -55,7 +55,7 @@
* Resets the right and bottom clip for this view.
*/
public void reset() {
- mClipRect.setEmpty();
+ mClipRect.set(-1, -1, -1, -1);
updateClipBounds();
}
@@ -90,9 +90,9 @@
}
private void updateClipBounds() {
- mClipBounds.set(mClipRect.left, mClipRect.top,
- mSourceView.getWidth() - mClipRect.right,
- mSourceView.getHeight() - mClipRect.bottom);
+ mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top),
+ mSourceView.getWidth() - Math.max(0, mClipRect.right),
+ mSourceView.getHeight() - Math.max(0, mClipRect.bottom));
mSourceView.setClipBounds(mClipBounds);
mSourceView.invalidateOutline();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
index 2351aa3..7f907ef 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -16,9 +16,12 @@
package com.android.systemui.recents.views;
+import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
+
+import com.android.systemui.R;
import com.android.systemui.recents.model.Task;
import java.util.Collections;
@@ -36,6 +39,14 @@
// Optimization, allows for quick lookup of task -> rect
private HashMap<Task.TaskKey, RectF> mTaskRectMap = new HashMap<>();
+ private int mTaskPadding;
+
+ public FreeformWorkspaceLayoutAlgorithm(Context context) {
+ // This is applied to the edges of each task
+ mTaskPadding = context.getResources().getDimensionPixelSize(
+ R.dimen.recents_freeform_workspace_task_padding) / 2;
+ }
+
/**
* Updates the layout for each of the freeform workspace tasks. This is called after the stack
* layout is updated.
@@ -117,6 +128,7 @@
rowLeft = defaultRowLeft;
}
RectF rect = new RectF(rowLeft, rowTop, rowLeft + width, rowTop + rowHeight);
+ rect.inset(mTaskPadding, mTaskPadding);
rowLeft += width;
mTaskRectMap.put(task.key, rect);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 96b1a41..0af7c1e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -157,7 +157,7 @@
ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture,
final ActivityOptions.OnAnimationStartedListener animStartedListener) {
SystemServicesProxy ssp = Recents.getSystemServices();
- if (ssp.startActivityFromRecents(mContext, task.key.id, task.activityLabel, opts)) {
+ if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
// Keep track of the index of the task launch
int taskIndexFromFront = 0;
int taskIndex = stack.indexOfStackTask(task);
@@ -311,7 +311,7 @@
Bitmap b = null;
if (addHeaderBitmap) {
float scale = transform.scale;
- int fromHeaderWidth = (int) (taskView.mHeaderView.getMeasuredWidth() * scale);
+ int fromHeaderWidth = (int) (transform.rect.width());
int fromHeaderHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight,
Bitmap.Config.ARGB_8888);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 36acc28..ad1ab14 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -32,8 +32,8 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-
import com.android.internal.logging.MetricsLogger;
+import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
@@ -47,14 +47,17 @@
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
+import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
@@ -70,36 +73,34 @@
* This view is the the top level layout that contains TaskStacks (which are laid out according
* to their SpaceNode bounds.
*/
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
+public class RecentsView extends FrameLayout {
private static final String TAG = "RecentsView";
private static final boolean DEBUG = false;
- Handler mHandler;
+ private final Handler mHandler;
- TaskStack mStack;
- TaskStackView mTaskStackView;
- RecentsAppWidgetHostView mSearchBar;
- View mHistoryButton;
- boolean mAwaitingFirstLayout = true;
- boolean mLastTaskLaunchedWasFreeform;
+ private TaskStack mStack;
+ private TaskStackView mTaskStackView;
+ private RecentsAppWidgetHostView mSearchBar;
+ private TextView mHistoryButton;
+ private View mEmptyView;
+ private boolean mAwaitingFirstLayout = true;
+ private boolean mLastTaskLaunchedWasFreeform;
+ private Rect mSystemInsets = new Rect();
- RecentsTransitionHelper mTransitionHelper;
- RecentsViewTouchHandler mTouchHandler;
- TaskStack.DockState[] mVisibleDockStates = {
+ private RecentsTransitionHelper mTransitionHelper;
+ private RecentsViewTouchHandler mTouchHandler;
+ private TaskStack.DockState[] mVisibleDockStates = {
TaskStack.DockState.LEFT,
TaskStack.DockState.TOP,
TaskStack.DockState.RIGHT,
TaskStack.DockState.BOTTOM,
};
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
- private int mHistoryTransitionDuration;
-
- Rect mSystemInsets = new Rect();
-
- final FlingAnimationUtils mFlingAnimationUtils;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mFastOutLinearInInterpolator;
+ private final FlingAnimationUtils mFlingAnimationUtils;
public RecentsView(Context context) {
this(context, null);
@@ -123,35 +124,34 @@
com.android.internal.R.interpolator.fast_out_slow_in);
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.fast_out_linear_in);
- mHistoryTransitionDuration = res.getInteger(R.integer.recents_history_transition_duration);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
LayoutInflater inflater = LayoutInflater.from(context);
- mHistoryButton = inflater.inflate(R.layout.recents_history_button, this, false);
+ mHistoryButton = (TextView) inflater.inflate(R.layout.recents_history_button, this, false);
mHistoryButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EventBus.getDefault().send(new ShowHistoryEvent());
}
});
+ addView(mHistoryButton);
+ mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
+ addView(mEmptyView);
}
/** Set/get the bsp root node */
public void setTaskStack(TaskStack stack) {
RecentsConfiguration config = Recents.getConfiguration();
+ RecentsActivityLaunchState launchState = config.getLaunchState();
mStack = stack;
- // Disable reusing task stack views until the visibility bug is fixed. b/25998134
- if (false && config.getLaunchState().launchedReuseTaskStackViews) {
+ if (launchState.launchedReuseTaskStackViews) {
if (mTaskStackView != null) {
// If onRecentsHidden is not triggered, we need to the stack view again here
mTaskStackView.reset();
mTaskStackView.setStack(stack);
- removeView(mTaskStackView);
- addView(mTaskStackView);
} else {
mTaskStackView = new TaskStackView(getContext(), stack);
- mTaskStackView.setCallbacks(this);
addView(mTaskStackView);
}
} else {
@@ -159,13 +159,14 @@
removeView(mTaskStackView);
}
mTaskStackView = new TaskStackView(getContext(), stack);
- mTaskStackView.setCallbacks(this);
addView(mTaskStackView);
}
- if (indexOfChild(mHistoryButton) == -1) {
- addView(mHistoryButton);
+
+ // Update the top level view's visibilities
+ if (stack.getStackTaskCount() > 0) {
+ hideEmptyView();
} else {
- mHistoryButton.bringToFront();
+ showEmptyView();
}
// Trigger a new layout
@@ -216,8 +217,8 @@
Task task = mTaskStackView.getFocusedTask();
if (task != null) {
TaskView taskView = mTaskStackView.getChildViewForTask(task);
- onTaskViewClicked(mTaskStackView, taskView, stack, task, false, null,
- INVALID_STACK_ID);
+ EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
+ INVALID_STACK_ID, false));
return true;
}
}
@@ -231,8 +232,8 @@
Task task = stack.getLaunchTarget();
if (task != null) {
TaskView taskView = mTaskStackView.getChildViewForTask(task);
- onTaskViewClicked(mTaskStackView, taskView, stack, task, false, null,
- INVALID_STACK_ID);
+ EventBus.getDefault().send(new LaunchTaskEvent(taskView, task, null,
+ INVALID_STACK_ID, false));
return true;
}
}
@@ -249,8 +250,8 @@
for (int j = 0; j < taskViewCount; j++) {
TaskView tv = taskViews.get(j);
if (tv.getTask() == task) {
- onTaskViewClicked(mTaskStackView, tv, stack, task, false,
- taskBounds, destinationStack);
+ EventBus.getDefault().send(new LaunchTaskEvent(tv, task, taskBounds,
+ destinationStack, false));
return true;
}
}
@@ -309,13 +310,33 @@
return mSearchBar != null && !mSearchBar.isReinflateRequired();
}
- /** Sets the visibility of the search bar */
- public void setSearchBarVisibility(int visibility) {
+ /**
+ * Hides the task stack and shows the empty view.
+ */
+ public void showEmptyView() {
+ if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
+ mSearchBar.setVisibility(View.INVISIBLE);
+ }
+ mTaskStackView.setVisibility(View.INVISIBLE);
+ mEmptyView.setVisibility(View.VISIBLE);
+ mEmptyView.bringToFront();
+ mHistoryButton.bringToFront();
+ }
+
+ /**
+ * Shows the task stack and hides the empty view.
+ */
+ public void hideEmptyView() {
+ mEmptyView.setVisibility(View.INVISIBLE);
+ mTaskStackView.setVisibility(View.VISIBLE);
+ if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
+ mSearchBar.setVisibility(View.VISIBLE);
+ }
+ mTaskStackView.bringToFront();
if (mSearchBar != null) {
- mSearchBar.setVisibility(visibility);
- // Always bring the search bar to the top
mSearchBar.bringToFront();
}
+ mHistoryButton.bringToFront();
}
/**
@@ -366,6 +387,10 @@
mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
}
+ // Measure the empty view
+ measureChild(mEmptyView, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+
// Measure the history button with the full space above the stack, but width-constrained
// to the stack
Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
@@ -373,6 +398,7 @@
MeasureSpec.makeMeasureSpec(historyButtonRect.width(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(historyButtonRect.height(),
MeasureSpec.EXACTLY));
+
setMeasuredDimension(width, height);
}
@@ -397,6 +423,9 @@
mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
}
+ // Layout the empty view
+ mEmptyView.layout(left, top, right, bottom);
+
// Layout the history button left-aligned with the stack, but offset from the top of the
// view
Rect historyButtonRect = mTaskStackView.mLayoutAlgorithm.mHistoryButtonRect;
@@ -456,19 +485,14 @@
return super.verifyDrawable(who);
}
- /**** TaskStackView.TaskStackCallbacks Implementation ****/
-
- @Override
- public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
- final TaskStack stack, final Task task, final boolean lockToTask,
- final Rect bounds, int destinationStack) {
- mLastTaskLaunchedWasFreeform = task.isFreeformTask();
- mTransitionHelper.launchTaskFromRecents(stack, task, stackView, tv, lockToTask, bounds,
- destinationStack);
- }
-
/**** EventBus Events ****/
+ public final void onBusEvent(LaunchTaskEvent event) {
+ mLastTaskLaunchedWasFreeform = event.task.isFreeformTask();
+ mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackView, event.taskView,
+ event.screenPinningRequested, event.targetTaskBounds, event.targetTaskStack);
+ }
+
public final void onBusEvent(DragStartEvent event) {
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
TaskStack.DockState.NONE.viewState.dockAreaAlpha);
@@ -545,12 +569,21 @@
public final void onBusEvent(ShowHistoryEvent event) {
// Hide the history button when the history view is shown
- hideHistoryButton(mHistoryTransitionDuration);
+ hideHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
+ event.getAnimationTrigger());
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ setAlpha(0f);
+ }
+ });
}
public final void onBusEvent(HideHistoryEvent event) {
// Show the history button when the history view is hidden
- showHistoryButton(mHistoryTransitionDuration);
+ setAlpha(1f);
+ showHistoryButton(getResources().getInteger(R.integer.recents_history_transition_duration),
+ event.getAnimationTrigger());
}
public final void onBusEvent(ShowHistoryButtonEvent event) {
@@ -561,35 +594,50 @@
hideHistoryButton(100);
}
- public final void onBusEvent(DebugFlagsChangedEvent event) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (!debugFlags.isHistoryEnabled()) {
- hideHistoryButton(100);
- }
+ public final void onBusEvent(TaskStackUpdatedEvent event) {
+ mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
+ mStack.createAffiliatedGroupings(getContext());
}
/**
* Shows the history button.
*/
- private void showHistoryButton(int duration) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (!debugFlags.isHistoryEnabled()) {
- return;
- }
+ private void showHistoryButton(final int duration) {
+ ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
+ showHistoryButton(duration, postAnimationTrigger);
+ postAnimationTrigger.flushLastDecrementRunnables();
+ }
+ private void showHistoryButton(final int duration,
+ final ReferenceCountedTrigger postHideHistoryAnimationTrigger) {
mHistoryButton.setVisibility(View.VISIBLE);
- mHistoryButton.animate()
- .alpha(1f)
- .setDuration(duration)
- .setInterpolator(mFastOutSlowInInterpolator)
- .withLayer()
- .start();
+ mHistoryButton.setAlpha(0f);
+ mHistoryButton.setText(getContext().getString(R.string.recents_history_label_format,
+ mStack.getHistoricalTasks().size()));
+ postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ @Override
+ public void run() {
+ mHistoryButton.animate()
+ .alpha(1f)
+ .setDuration(duration)
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .withLayer()
+ .start();
+ }
+ });
}
/**
* Hides the history button.
*/
private void hideHistoryButton(int duration) {
+ ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger();
+ hideHistoryButton(duration, postAnimationTrigger);
+ postAnimationTrigger.flushLastDecrementRunnables();
+ }
+
+ private void hideHistoryButton(int duration,
+ final ReferenceCountedTrigger postHideStackAnimationTrigger) {
mHistoryButton.animate()
.alpha(0f)
.setDuration(duration)
@@ -598,10 +646,12 @@
@Override
public void run() {
mHistoryButton.setVisibility(View.INVISIBLE);
+ postHideStackAnimationTrigger.decrement();
}
})
.withLayer()
.start();
+ postHideStackAnimationTrigger.increment();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 2920295..318801d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -188,12 +188,8 @@
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
if (mDragging) {
- ReferenceCountedTrigger postAnimationTrigger = new ReferenceCountedTrigger(
- mRv.getContext(), null, null, null);
- postAnimationTrigger.increment();
EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
- mLastDropTarget, postAnimationTrigger));
- postAnimationTrigger.decrement();
+ mLastDropTarget));
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 5a09ee4..f84eb53 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -62,13 +62,14 @@
* Prepares the scrim views for animating when entering Recents. This will be called before
* the first draw.
*/
- public void prepareEnterRecentsAnimation() {
+ public void prepareEnterRecentsAnimation(boolean hasStatusBarScrim, boolean animateStatusBarScrim,
+ boolean hasNavBarScrim, boolean animateNavBarScrim) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
- mHasNavBarScrim = launchState.hasNavBarScrim();
- mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
- mHasStatusBarScrim = launchState.hasStatusBarScrim();
- mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim();
+ mHasNavBarScrim = hasStatusBarScrim;
+ mShouldAnimateStatusBarScrim = animateStatusBarScrim;
+ mHasStatusBarScrim = hasNavBarScrim;
+ mShouldAnimateNavBarScrim = animateNavBarScrim;
mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
View.VISIBLE : View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index f599f52..9d391b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -118,7 +118,7 @@
*/
public static class StackState {
- public static final StackState FREEFORM_ONLY = new StackState(1f, 0);
+ public static final StackState FREEFORM_ONLY = new StackState(1f, 255);
public static final StackState STACK_ONLY = new StackState(0f, 0);
public static final StackState SPLIT = new StackState(0.5f, 255);
@@ -294,7 +294,7 @@
mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
mContext = context;
- mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm();
+ mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.linear_out_slow_in);
}
@@ -333,7 +333,6 @@
* including the search bar.
*/
public void initialize(Rect taskStackBounds, StackState state) {
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
RecentsConfiguration config = Recents.getConfiguration();
int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
int heightPadding = mContext.getResources().getDimensionPixelSize(
@@ -355,9 +354,7 @@
/ (taskStackBounds.height() - mSystemInsets.bottom);
int width = mStackRect.width();
int minHeight = mStackRect.height() - mFocusedPeekHeight - mStackBottomOffset;
- int height = debugFlags.isFullscreenThumbnailsEnabled()
- ? (int) Math.min(width / aspect, minHeight)
- : width;
+ int height = (int) Math.min(width / aspect, minHeight);
mTaskRect.set(mStackRect.left, mStackRect.top,
mStackRect.left + width, mStackRect.top + height);
@@ -499,8 +496,7 @@
public float getDefaultFocusState() {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
RecentsDebugFlags debugFlags = Recents.getDebugFlags();
- if (launchState.launchedWithAltTab ||
- (debugFlags.isPageOnToggleEnabled() && debugFlags.isInitialStatePaging())) {
+ if (launchState.launchedWithAltTab || debugFlags.isInitialStatePaging()) {
return 1f;
}
return 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 350bc2b..94fae13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -27,6 +27,8 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
+import android.os.Parcelable;
+import android.provider.Settings;
import android.util.IntProperty;
import android.util.Log;
import android.util.Property;
@@ -43,18 +45,19 @@
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.RecentsDebugFlags;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
import com.android.systemui.recents.events.activity.HideHistoryButtonEvent;
import com.android.systemui.recents.events.activity.HideHistoryEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.PackagesChangedEvent;
import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
import com.android.systemui.recents.events.activity.ShowHistoryEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -91,10 +94,18 @@
private final static String TAG = "TaskStackView";
private final static boolean DEBUG = false;
+ private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
+ private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
+ "saved_instance_state_layout_focused_state";
+ private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
+ "saved_instance_state_layout_stack_scroll";
+
// The thresholds at which to show/hide the history button.
private static final float SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f;
+ private static final int DEFAULT_SYNC_STACK_DURATION = 200;
+
public static final Property<Drawable, Integer> DRAWABLE_ALPHA =
new IntProperty<Drawable>("drawableAlpha") {
@Override
@@ -108,17 +119,10 @@
}
};
- /** The TaskView callbacks */
- interface TaskStackViewCallbacks {
- public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
- boolean lockToTask, Rect bounds, int destinationStack);
- }
-
TaskStack mStack;
TaskStackLayoutAlgorithm mLayoutAlgorithm;
TaskStackViewScroller mStackScroller;
TaskStackViewTouchHandler mTouchHandler;
- TaskStackViewCallbacks mCb;
GradientDrawable mFreeformWorkspaceBackground;
ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
ViewPool<TaskView, Task> mViewPool;
@@ -146,7 +150,9 @@
List<TaskView> mImmutableTaskViews = new ArrayList<>();
List<TaskView> mTmpTaskViews = new ArrayList<>();
LayoutInflater mInflater;
+
boolean mTouchExplorationEnabled;
+ boolean mScreenPinningEnabled;
Interpolator mFastOutSlowInInterpolator;
@@ -212,19 +218,17 @@
R.drawable.recents_freeform_workspace_bg);
mFreeformWorkspaceBackground.setCallback(this);
if (ssp.hasFreeformWorkspaceSupport()) {
- setBackgroundColor(getContext().getColor(R.color.recents_freeform_workspace_bg_color));
+ mFreeformWorkspaceBackground.setColor(
+ getContext().getColor(R.color.recents_freeform_workspace_bg_color));
}
}
- /** Sets the callbacks */
- void setCallbacks(TaskStackViewCallbacks cb) {
- mCb = cb;
- }
-
@Override
protected void onAttachedToWindow() {
SystemServicesProxy ssp = Recents.getSystemServices();
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+ mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
+ Settings.System.LOCK_TO_APP_ENABLED) != 0;
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
super.onAttachedToWindow();
}
@@ -673,12 +677,7 @@
if (scrollToTask) {
// TODO: Center the newly focused task view, only if not freeform
- RecentsDebugFlags debugFlags = Recents.getDebugFlags();
float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask);
- if (!debugFlags.isFullscreenThumbnailsEnabled()) {
- newScroll -= 0.5f;
- }
- newScroll = mStackScroller.getBoundedStackScroll(newScroll);
if (Float.compare(newScroll, mStackScroller.getStackScroll()) != 0) {
mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
focusTaskRunnable);
@@ -803,7 +802,7 @@
TaskView frontMostTask = taskViews.get(taskViewCount - 1);
event.setFromIndex(mStack.indexOfStackTask(backMostTask.getTask()));
event.setToIndex(mStack.indexOfStackTask(frontMostTask.getTask()));
- event.setContentDescription(frontMostTask.getTask().activityLabel);
+ event.setContentDescription(frontMostTask.getTask().title);
}
event.setItemCount(mStack.getStackTaskCount());
event.setScrollY(mStackScroller.mScroller.getCurrY());
@@ -828,6 +827,24 @@
}
@Override
+ protected Parcelable onSaveInstanceState() {
+ Bundle savedState = new Bundle();
+ savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
+ savedState.putFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
+ savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
+ return super.onSaveInstanceState();
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ Bundle savedState = (Bundle) state;
+ super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
+
+ mLayoutAlgorithm.setFocusState(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
+ mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
+ }
+
+ @Override
public CharSequence getAccessibilityClassName() {
return TaskStackView.class.getName();
}
@@ -1009,11 +1026,9 @@
if (launchTargetTask != null) {
occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(task,
launchTargetTask);
- hideTask = SystemServicesProxy.isFreeformStack(launchTargetTask.key.stackId) &&
- SystemServicesProxy.isFreeformStack(task.key.stackId);
+ hideTask = launchTargetTask.isFreeformTask() && task.isFreeformTask();
}
- tv.prepareEnterRecentsAnimation(task.isLaunchTarget, hideTask, occludesLaunchTarget,
- offscreenY);
+ tv.prepareEnterRecentsAnimation(hideTask, occludesLaunchTarget, offscreenY);
}
// If the enter animation started already and we haven't completed a layout yet, do the
@@ -1040,8 +1055,11 @@
}
// Update the history button visibility
- if (mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
+ if (shouldShowHistoryButton() &&
+ mStackScroller.getStackScroll() < SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
EventBus.getDefault().send(new ShowHistoryButtonEvent());
+ } else {
+ EventBus.getDefault().send(new HideHistoryButtonEvent());
}
// Start dozing
@@ -1073,6 +1091,7 @@
ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
+ ctx.isScreenPinningEnabled = mScreenPinningEnabled;
ctx.updateListener = mRequestUpdateClippingListener;
mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
ctx.currentTaskTransform, null);
@@ -1177,7 +1196,8 @@
public boolean launchFreeformTasks() {
Task frontTask = mStack.getStackFrontMostTask();
if (frontTask != null && frontTask.isFreeformTask()) {
- onTaskViewClicked(getChildViewForTask(frontTask), frontTask, false);
+ EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
+ frontTask, null, INVALID_STACK_ID, false));
return true;
}
return false;
@@ -1186,6 +1206,15 @@
/**** TaskStackCallbacks Implementation ****/
@Override
+ public void onStackTaskAdded(TaskStack stack, Task newTask) {
+ // Update the min/max scroll and animate other task views into their new positions
+ updateLayout(true);
+
+ // Animate all the tasks into place
+ requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
+ }
+
+ @Override
public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
Task newFrontMostTask) {
if (mFocusedTask == removedTask) {
@@ -1231,7 +1260,7 @@
}
// Animate all the tasks into place
- requestSynchronizeStackViewsWithModel(200);
+ requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
} else {
// Remove the view associated with this task, we can't rely on updateTransforms
// to work here because the task is no longer in the list
@@ -1244,16 +1273,14 @@
updateLayout(true);
// Animate all the tasks into place
- requestSynchronizeStackViewsWithModel(200);
+ requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
}
- // Update the new front most task
- if (newFrontMostTask != null) {
+ // Update the new front most task's action button
+ if (mScreenPinningEnabled && newFrontMostTask != null) {
TaskView frontTv = getChildViewForTask(newFrontMostTask);
if (frontTv != null) {
- frontTv.onTaskBound(newFrontMostTask);
- frontTv.fadeInActionButton(getResources().getInteger(
- R.integer.recents_task_enter_from_app_duration));
+ frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
}
}
@@ -1280,7 +1307,7 @@
@Override
public void prepareViewToEnterPool(TaskView tv) {
- Task task = tv.getTask();
+ final Task task = tv.getTask();
// Report that this tasks's data is no longer being used
Recents.getTaskLoader().unloadTaskData(task);
@@ -1290,14 +1317,13 @@
// Update the task views list after removing the task view
updateTaskViewsList();
- // Reset the view properties
+ // Reset the view properties and view state
tv.resetViewProperties();
-
- // Reset the focused view state
tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-
- // Reset the clip state of the task view
tv.setClipViewInStack(false);
+ if (mScreenPinningEnabled) {
+ tv.hideActionButton();
+ }
}
@Override
@@ -1338,6 +1364,11 @@
if (mFocusedTask == task) {
tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
}
+
+ // Restore the action button visibility if it is the front most task view
+ if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+ tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+ }
}
@Override
@@ -1348,16 +1379,6 @@
/**** TaskViewCallbacks Implementation ****/
@Override
- public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) {
- // Cancel any doze triggers
- mUIDozeTrigger.stopDozing();
-
- if (mCb != null) {
- mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask, null, INVALID_STACK_ID);
- }
- }
-
- @Override
public void onTaskViewClipStateChanged(TaskView tv) {
requestUpdateStackViewsClip();
}
@@ -1370,7 +1391,8 @@
requestSynchronizeStackViewsWithModel();
postInvalidateOnAnimation();
- if (prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
+ if (shouldShowHistoryButton() &&
+ prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD &&
curScroll <= SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD) {
EventBus.getDefault().send(new ShowHistoryButtonEvent());
} else if (prevScroll < HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD &&
@@ -1408,8 +1430,14 @@
}
}
+ public final void onBusEvent(LaunchTaskEvent event) {
+ // Cancel any doze triggers once a task is launched
+ mUIDozeTrigger.stopDozing();
+ }
+
public final void onBusEvent(DismissTaskViewEvent event) {
removeTaskViewFromStack(event.taskView);
+ EventBus.getDefault().send(new DismissTaskEvent(event.task));
}
public final void onBusEvent(FocusNextTaskViewEvent event) {
@@ -1472,7 +1500,6 @@
(!isFreeformTask && event.dropTarget == mFreeformWorkspaceDropTarget) ||
(isFreeformTask && event.dropTarget == mStackDropTarget);
- event.postAnimationTrigger.increment();
if (hasChangedStacks) {
// Move the task to the right position in the stack (ie. the front of the stack if
// freeform or the front of the stack if fullscreen). Note, we MUST move the tasks
@@ -1485,7 +1512,7 @@
updateLayout(true);
// Move the task to the new stack in the system after the animation completes
- event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ event.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -1493,8 +1520,8 @@
}
});
}
- event.taskView.animate()
- .withEndAction(event.postAnimationTrigger.decrementAsRunnable());
+ event.getAnimationTrigger().increment();
+ event.taskView.animate().withEndAction(event.getAnimationTrigger().decrementAsRunnable());
// We translated the view but we need to animate it back from the current layout-space rect
// to its final layout-space rect
@@ -1517,6 +1544,10 @@
}
public final void onBusEvent(IterateRecentsEvent event) {
+ if (!mEnterAnimationComplete) {
+ // Cancel the previous task's window transition before animating the focused state
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
+ }
mLayoutAlgorithm.animateFocusState(mLayoutAlgorithm.getDefaultFocusState());
}
@@ -1530,39 +1561,54 @@
for (int i = 0; i < taskViewCount; i++) {
TaskView tv = taskViews.get(i);
Task task = tv.getTask();
- if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
+ if (task.isFreeformTask()) {
tv.setVisibility(event.visible ? View.VISIBLE : View.INVISIBLE);
}
}
}
public final void onBusEvent(ShowHistoryEvent event) {
+ // The history view's animation will be deferred until all the stack task views are animated
+ // away
+ int historyTransitionDuration =
+ getResources().getInteger(R.integer.recents_history_transition_duration);
List<TaskView> taskViews = getTaskViews();
int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) {
TaskView tv = taskViews.get(i);
tv.animate()
.alpha(0f)
- .setDuration(200)
+ .setDuration(historyTransitionDuration)
.setUpdateListener(null)
.setListener(null)
.withLayer()
+ .withEndAction(event.getAnimationTrigger().decrementAsRunnable())
.start();
+ event.getAnimationTrigger().increment();
}
}
public final void onBusEvent(HideHistoryEvent event) {
+ // The stack task view animations will be deferred until the history view has been animated
+ // away
+ final int historyTransitionDuration =
+ getResources().getInteger(R.integer.recents_history_transition_duration);
List<TaskView> taskViews = getTaskViews();
int taskViewCount = taskViews.size();
for (int i = taskViewCount - 1; i >= 0; i--) {
- TaskView tv = taskViews.get(i);
- tv.animate()
- .alpha(1f)
- .setDuration(200)
- .setUpdateListener(null)
- .setListener(null)
- .withLayer()
- .start();
+ final TaskView tv = taskViews.get(i);
+ event.addPostAnimationCallback(new Runnable() {
+ @Override
+ public void run() {
+ tv.animate()
+ .alpha(1f)
+ .setDuration(historyTransitionDuration)
+ .setUpdateListener(null)
+ .setListener(null)
+ .withLayer()
+ .start();
+ }
+ });
}
}
@@ -1575,7 +1621,7 @@
// Announce for accessibility
tv.announceForAccessibility(getContext().getString(
- R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel));
+ R.string.accessibility_recents_item_dismissed, tv.getTask().title));
// Remove the task from the stack
mStack.removeTask(task);
@@ -1626,4 +1672,11 @@
}
return -1;
}
+
+ /**
+ * @return whether the history button should be visible
+ */
+ private boolean shouldShowHistoryButton() {
+ return !mStack.getHistoricalTasks().isEmpty();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 1e2227e..14909c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -45,6 +45,7 @@
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
@@ -54,6 +55,8 @@
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
/* A task view */
public class TaskView extends FrameLayout implements Task.TaskCallbacks,
View.OnClickListener, View.OnLongClickListener {
@@ -63,8 +66,7 @@
/** The TaskView callbacks */
interface TaskViewCallbacks {
- public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
- public void onTaskViewClipStateChanged(TaskView tv);
+ void onTaskViewClipStateChanged(TaskView tv);
}
float mTaskProgress;
@@ -136,6 +138,7 @@
setBackground(new FakeShadowDrawable(res, config));
}
setOutlineProvider(mViewBounds);
+ setOnLongClickListener(this);
}
/** Set callback */
@@ -173,8 +176,10 @@
public void getOutline(View view, Outline outline) {
// Set the outline to match the FAB background
outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
+ outline.setAlpha(0.35f);
}
});
+ mActionButtonView.setOnClickListener(this);
mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
}
@@ -278,7 +283,6 @@
/** Resets this view's properties */
void resetViewProperties() {
setDim(0);
- setLayerType(View.LAYER_TYPE_NONE, null);
setVisibility(View.VISIBLE);
getViewBounds().reset();
TaskViewTransform.reset(this);
@@ -292,8 +296,8 @@
/** Prepares this task view for the enter-recents animations. This is called earlier in the
* first layout because the actual animation into recents may take a long time. */
- void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
- boolean occludesLaunchTarget, int offscreenY) {
+ void prepareEnterRecentsAnimation(boolean hideTask, boolean occludesLaunchTarget,
+ int offscreenY) {
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
int initialDim = getDim();
@@ -302,7 +306,7 @@
} else if (launchState.launchedHasConfigurationChanged) {
// Just load the views as-is
} else if (launchState.launchedFromAppWithThumbnail) {
- if (isTaskViewLaunchTargetTask) {
+ if (mTask.isLaunchTarget) {
// Set the dim to 0 so we can animate it in
initialDim = 0;
// Hide the action button
@@ -340,13 +344,16 @@
if (launchState.launchedFromAppWithThumbnail) {
if (mTask.isLaunchTarget) {
- // Immediately start the dim animation
+ ctx.postAnimationTrigger.increment();
+ // Start the dim animation
animateDimToProgress(taskViewEnterFromAppDuration,
ctx.postAnimationTrigger.decrementOnAnimationEnd());
- ctx.postAnimationTrigger.increment();
- // Animate the action button in
- fadeInActionButton(taskViewEnterFromAppDuration);
+ // Start the action button animation
+ if (ctx.isScreenPinningEnabled) {
+ showActionButton(true /* fadeIn */,
+ taskViewEnterFromAppDuration /* fadeInDuration */);
+ }
} else {
// Animate the task up if it was occluding the launch target
if (ctx.currentTaskOccludesLaunchTarget) {
@@ -413,17 +420,6 @@
animate().cancel();
}
- public void fadeInActionButton(int duration) {
- // Hide the action button
- mActionButtonView.setAlpha(0f);
-
- // Animate the action button in
- mActionButtonView.animate().alpha(1f)
- .setDuration(duration)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
- .start();
- }
-
/** Animates this task view as it leaves recents by pressing home. */
void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
int taskViewExitToHomeDuration = getResources().getInteger(
@@ -468,8 +464,9 @@
.alpha(0f)
.setStartDelay(0)
.setDuration(taskViewExitToAppDuration)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(PhoneStatusBar.ALPHA_OUT)
.withEndAction(postAnimRunnable)
+ .withLayer()
.start();
} else {
// Hide the dismiss button
@@ -644,14 +641,12 @@
setDim(getDimFromTaskProgress());
}
- /**** View focus state ****/
-
/**
* Explicitly sets the focused state of this task.
*/
public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) {
if (DEBUG) {
- Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused +
+ Log.d(TAG, "setFocusedState: " + mTask.title + " focused: " + isFocused +
" animated: " + animated + " requestViewFocus: " + requestViewFocus +
" isFocused(): " + isFocused() +
" isAccessibilityFocused(): " + isAccessibilityFocused());
@@ -672,31 +667,50 @@
}
}
+ /**
+ * Shows the action button.
+ * @param fadeIn whether or not to animate the action button in.
+ * @param fadeInDuration the duration of the action button animation, only used if
+ * {@param fadeIn} is true.
+ */
+ public void showActionButton(boolean fadeIn, int fadeInDuration) {
+ mActionButtonView.setVisibility(View.VISIBLE);
+
+ if (fadeIn) {
+ if (mActionButtonView.getAlpha() < 1f) {
+ mActionButtonView.setAlpha(0f);
+ mActionButtonView.animate().alpha(1f)
+ .setDuration(fadeInDuration)
+ .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .withLayer()
+ .start();
+ }
+ } else {
+ mActionButtonView.setAlpha(1f);
+ }
+ }
+
+ /**
+ * Immediately hides the action button.
+ */
+ public void hideActionButton() {
+ mActionButtonView.setVisibility(View.INVISIBLE);
+ }
+
/**** TaskCallbacks Implementation ****/
/** Binds this task view to the task */
public void onTaskBound(Task t) {
mTask = t;
- mTask.setCallbacks(this);
-
- // Hide the action button if lock to app is disabled for this view
- int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
- if (mActionButtonView.getVisibility() != lockButtonVisibility) {
- mActionButtonView.setVisibility(lockButtonVisibility);
- requestLayout();
- }
+ mTask.addCallback(this);
}
@Override
- public void onTaskDataLoaded() {
+ public void onTaskDataLoaded(Task task) {
if (mThumbnailView != null && mHeaderView != null) {
// Bind each of the views to the new task data
mThumbnailView.rebindToTask(mTask);
mHeaderView.rebindToTask(mTask);
-
- // Rebind any listeners
- mActionButtonView.setOnClickListener(this);
- setOnLongClickListener(this);
}
mTaskDataLoaded = true;
}
@@ -705,11 +719,9 @@
public void onTaskDataUnloaded() {
if (mThumbnailView != null && mHeaderView != null) {
// Unbind each of the views from the task data and remove the task callback
- mTask.setCallbacks(null);
+ mTask.removeCallback(this);
mThumbnailView.unbindFromTask();
mHeaderView.unbindFromTask();
- // Unbind any listeners
- mActionButtonView.setOnClickListener(null);
}
mTaskDataLoaded = false;
}
@@ -723,13 +735,14 @@
@Override
public void onClick(final View v) {
+ boolean screenPinningRequested = false;
if (v == mActionButtonView) {
// Reset the translation of the action button before we animate it out
mActionButtonView.setTranslationZ(0f);
+ screenPinningRequested = true;
}
- if (mCb != null) {
- mCb.onTaskViewClicked(this, mTask, (v == mActionButtonView));
- }
+ EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
+ screenPinningRequested));
}
/**** View.OnLongClickListener Implementation ****/
@@ -770,7 +783,7 @@
public final void onBusEvent(DragEndEvent event) {
if (!(event.dropTarget instanceof TaskStack.DockState)) {
- event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+ event.addPostAnimationCallback(new Runnable() {
@Override
public void run() {
// Animate the drag view back from where it is, to the view location, then after
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index d8220fd..9a2ffe7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -16,25 +16,20 @@
package com.android.systemui.recents.views;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.RippleDrawable;
-import android.graphics.drawable.ShapeDrawable;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewOutlineProvider;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -45,12 +40,16 @@
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.ResizeTaskEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.Task;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
/* The task bar view */
public class TaskViewHeader extends FrameLayout
@@ -61,8 +60,9 @@
// Header views
ImageView mMoveTaskButton;
ImageView mDismissButton;
- ImageView mApplicationIcon;
- TextView mActivityDescription;
+ ImageView mIconView;
+ TextView mTitleView;
+ int mMoveTaskTargetStackId = INVALID_STACK_ID;
// Header drawables
Rect mTaskViewRect = new Rect();
@@ -128,16 +128,16 @@
@Override
protected void onFinishInflate() {
// Initialize the icon and description views
- mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
- mApplicationIcon.setOnLongClickListener(this);
- mActivityDescription = (TextView) findViewById(R.id.activity_description);
+ mIconView = (ImageView) findViewById(R.id.icon);
+ mIconView.setOnLongClickListener(this);
+ mTitleView = (TextView) findViewById(R.id.title);
mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
mDismissButton.setOnClickListener(this);
mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
// Hide the backgrounds if they are ripple drawables
- if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
- mApplicationIcon.setBackground(null);
+ if (mIconView.getBackground() instanceof RippleDrawable) {
+ mIconView.setBackground(null);
}
mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(
@@ -157,24 +157,55 @@
*/
public void onTaskViewSizeChanged(int width, int height) {
mTaskViewRect.set(0, 0, width, height);
- if (mDismissButton.getMeasuredWidth() > (width - mApplicationIcon.getMeasuredWidth())) {
- mDismissButton.setAlpha(0f);
- } else {
- mDismissButton.setAlpha(1f);
- if (mDismissButton != null) {
- mDismissButton.setTranslationX(width - getMeasuredWidth());
+ boolean updateMoveTaskButton = mMoveTaskButton.getVisibility() != View.GONE;
+ int appIconWidth = mIconView.getMeasuredWidth();
+ int activityDescWidth = mTitleView.getMeasuredWidth();
+ int dismissIconWidth = mDismissButton.getMeasuredWidth();
+ int moveTaskIconWidth = mMoveTaskButton.getVisibility() == View.VISIBLE
+ ? mMoveTaskButton.getMeasuredWidth()
+ : 0;
+
+ // Priority-wise, we show the activity icon first, the dismiss icon if there is room, the
+ // move-task icon if there is room, and then finally, the activity label if there is room
+ if (width < (appIconWidth + dismissIconWidth)) {
+ mTitleView.setVisibility(View.INVISIBLE);
+ if (updateMoveTaskButton) {
+ mMoveTaskButton.setVisibility(View.INVISIBLE);
}
- }
- if (mActivityDescription.getMeasuredWidth() > (width -
- (mApplicationIcon.getMeasuredWidth() + mDismissButton.getMeasuredWidth()))) {
- mActivityDescription.setAlpha(0f);
+ mDismissButton.setVisibility(View.INVISIBLE);
+ } else if (width < (appIconWidth + dismissIconWidth + moveTaskIconWidth)) {
+ mTitleView.setVisibility(View.INVISIBLE);
+ if (updateMoveTaskButton) {
+ mMoveTaskButton.setVisibility(View.INVISIBLE);
+ }
+ mDismissButton.setVisibility(View.VISIBLE);
+ } else if (width < (appIconWidth + dismissIconWidth + moveTaskIconWidth +
+ activityDescWidth)) {
+ mTitleView.setVisibility(View.INVISIBLE);
+ if (updateMoveTaskButton) {
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ }
+ mDismissButton.setVisibility(View.VISIBLE);
} else {
- mActivityDescription.setAlpha(1f);
+ mTitleView.setVisibility(View.VISIBLE);
+ if (updateMoveTaskButton) {
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ }
+ mDismissButton.setVisibility(View.VISIBLE);
}
+ if (updateMoveTaskButton) {
+ mMoveTaskButton.setTranslationX(width - getMeasuredWidth());
+ }
+ mDismissButton.setTranslationX(width - getMeasuredWidth());
invalidate();
}
@Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ onTaskViewSizeChanged(mTaskViewRect.width(), mTaskViewRect.height());
+ }
+
+ @Override
protected void onDraw(Canvas canvas) {
// Draw the highlight at the top edge (but put the bottom edge just out of view)
float offset = (float) Math.ceil(mHighlightHeight / 2f);
@@ -197,19 +228,18 @@
/** Binds the bar view to the task */
public void rebindToTask(Task t) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
mTask = t;
// If an activity icon is defined, then we use that as the primary icon to show in the bar,
// otherwise, we fall back to the application icon
- if (t.activityIcon != null) {
- mApplicationIcon.setImageDrawable(t.activityIcon);
- } else if (t.applicationIcon != null) {
- mApplicationIcon.setImageDrawable(t.applicationIcon);
+ if (t.icon != null) {
+ mIconView.setImageDrawable(t.icon);
}
- if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
- mActivityDescription.setText(t.activityLabel);
+ if (!mTitleView.getText().toString().equals(t.title)) {
+ mTitleView.setText(t.title);
}
- mActivityDescription.setContentDescription(t.contentDescription);
+ mTitleView.setContentDescription(t.contentDescription);
// Try and apply the system ui tint
int existingBgColor = (getBackground() instanceof ColorDrawable) ?
@@ -222,65 +252,45 @@
R.color.recents_task_bar_light_text_color);
int taskBarViewDarkTextColor = getResources().getColor(
R.color.recents_task_bar_dark_text_color);
- mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
+ mTitleView.setTextColor(t.useLightOnPrimaryColor ?
taskBarViewLightTextColor : taskBarViewDarkTextColor);
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
t.contentDescription));
- updateResizeTaskBarIcon(t);
- mMoveTaskButton.setVisibility(View.VISIBLE);
- mMoveTaskButton.setOnClickListener(this);
+
+ // When freeform workspaces are enabled, then update the move-task button depending on the
+ // current task
+ if (ssp.hasFreeformWorkspaceSupport()) {
+ if (t.isFreeformTask()) {
+ mMoveTaskTargetStackId = FULLSCREEN_WORKSPACE_STACK_ID;
+ mMoveTaskButton.setImageResource(t.useLightOnPrimaryColor
+ ? R.drawable.recents_move_task_fullscreen_light
+ : R.drawable.recents_move_task_fullscreen_dark);
+ } else {
+ mMoveTaskTargetStackId = FREEFORM_WORKSPACE_STACK_ID;
+ mMoveTaskButton.setImageResource(t.useLightOnPrimaryColor
+ ? R.drawable.recents_move_task_freeform_light
+ : R.drawable.recents_move_task_freeform_dark);
+ }
+ mMoveTaskButton.setVisibility(View.VISIBLE);
+ mMoveTaskButton.setOnClickListener(this);
+ }
// In accessibility, a single click on the focused app info button will show it
- SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.isTouchExplorationEnabled()) {
- mApplicationIcon.setOnClickListener(this);
+ mIconView.setOnClickListener(this);
}
}
/** Unbinds the bar view from the task */
void unbindFromTask() {
mTask = null;
- mApplicationIcon.setImageDrawable(null);
- mApplicationIcon.setOnClickListener(null);
+ mIconView.setImageDrawable(null);
+ mIconView.setOnClickListener(null);
mMoveTaskButton.setOnClickListener(null);
}
- /** Updates the resize task bar button. */
- void updateResizeTaskBarIcon(Task t) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- Rect display = ssp.getWindowRect();
- Rect taskRect = ssp.getTaskBounds(t.key.id);
- int resId = R.drawable.star;
- if (display.equals(taskRect) || taskRect.isEmpty()) {
- resId = R.drawable.vector_drawable_place_fullscreen;
- } else {
- boolean top = display.top == taskRect.top;
- boolean bottom = display.bottom == taskRect.bottom;
- boolean left = display.left == taskRect.left;
- boolean right = display.right == taskRect.right;
- if (top && bottom && left) {
- resId = R.drawable.vector_drawable_place_left;
- } else if (top && bottom && right) {
- resId = R.drawable.vector_drawable_place_right;
- } else if (top && left && right) {
- resId = R.drawable.vector_drawable_place_top;
- } else if (bottom && left && right) {
- resId = R.drawable.vector_drawable_place_bottom;
- } else if (top && right) {
- resId = R.drawable.vector_drawable_place_top_right;
- } else if (top && left) {
- resId = R.drawable.vector_drawable_place_top_left;
- } else if (bottom && right) {
- resId = R.drawable.vector_drawable_place_bottom_right;
- } else if (bottom && left) {
- resId = R.drawable.vector_drawable_place_bottom_left;
- }
- }
- mMoveTaskButton.setImageResource(resId);
- }
-
/** Animates this task bar dismiss button when launching a task. */
void startLaunchTaskDismissAnimation(final Runnable postAnimationRunanble) {
if (mDismissButton.getVisibility() == View.VISIBLE) {
@@ -345,7 +355,7 @@
@Override
public void onClick(View v) {
- if (v == mApplicationIcon) {
+ if (v == mIconView) {
// In accessibility, a single click on the focused app info button will show it
EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
} else if (v == mDismissButton) {
@@ -356,13 +366,18 @@
MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
Constants.Metrics.DismissSourceHeaderButton);
} else if (v == mMoveTaskButton) {
- EventBus.getDefault().send(new ResizeTaskEvent(mTask));
+ TaskView tv = Utilities.findParent(this, TaskView.class);
+ Rect bounds = mMoveTaskTargetStackId == FREEFORM_WORKSPACE_STACK_ID
+ ? new Rect(mTaskViewRect)
+ : new Rect();
+ EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, bounds,
+ mMoveTaskTargetStackId, false));
}
}
@Override
public boolean onLongClick(View v) {
- if (v == mApplicationIcon) {
+ if (v == mIconView) {
EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 37d8cd6..8edfae0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -129,6 +129,7 @@
mBitmapShader = null;
mDrawPaint.setShader(null);
}
+ invalidate();
}
/** Updates the paint to draw the thumbnail. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index e1d80fd..eaef51c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -33,6 +33,8 @@
// These following properties are updated for each task view we start the enter animation on
+ // Whether or not screen pinning is enabled
+ boolean isScreenPinningEnabled;
// Whether or not the current task occludes the launch target
boolean currentTaskOccludesLaunchTarget;
// The task rect for the current stack
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 6ff7a3e..189e651 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,7 +17,8 @@
package com.android.systemui.stackdivider;
import android.content.res.Configuration;
-import android.view.IDockDividerVisibilityListener;
+import android.os.RemoteException;
+import android.view.IDockedStackListener;
import android.view.LayoutInflater;
import android.view.View;
@@ -49,7 +50,7 @@
putComponent(Divider.class, this);
mDockDividerVisibilityListener = new DockDividerVisibilityListener();
SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.registerDockDividerVisibilityListener(mDockDividerVisibilityListener);
+ ssp.registerDockedStackListener(mDockDividerVisibilityListener);
}
@Override
@@ -94,10 +95,15 @@
});
}
- class DockDividerVisibilityListener extends IDockDividerVisibilityListener.Stub {
+ class DockDividerVisibilityListener extends IDockedStackListener.Stub {
+
@Override
- public void onDockDividerVisibilityChanged(boolean visible) {
+ public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
updateVisibility(visible);
}
+
+ @Override
+ public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
new file mode 100644
index 0000000..5ef56f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.stackdivider;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+
+/**
+ * View for the handle in the docked stack divider.
+ */
+public class DividerHandleView extends ImageButton {
+
+ private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
+ = new Property<DividerHandleView, Integer>(Integer.class, "width") {
+
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentWidth;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentWidth = value;
+ object.invalidate();
+ }
+ };
+
+ private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY
+ = new Property<DividerHandleView, Integer>(Integer.class, "height") {
+
+ @Override
+ public Integer get(DividerHandleView object) {
+ return object.mCurrentHeight;
+ }
+
+ @Override
+ public void set(DividerHandleView object, Integer value) {
+ object.mCurrentHeight = value;
+ object.invalidate();
+ }
+ };
+
+ private final Paint mPaint = new Paint();
+ private final int mWidth;
+ private final int mHeight;
+ private final int mCircleDiameter;
+ private final Interpolator mFastOutSlowInInterpolator;
+ private int mCurrentWidth;
+ private int mCurrentHeight;
+ private AnimatorSet mAnimator;
+
+ public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
+ mPaint.setAntiAlias(true);
+ mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
+ mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+ mCurrentWidth = mWidth;
+ mCurrentHeight = mHeight;
+ mCircleDiameter = (mWidth + mHeight) / 3;
+ mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+ android.R.interpolator.fast_out_slow_in);
+ }
+
+ public void setTouching(boolean touching, boolean animate) {
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ mAnimator = null;
+ }
+ if (!animate) {
+ if (touching) {
+ mCurrentWidth = mCircleDiameter;
+ mCurrentHeight = mCircleDiameter;
+ } else {
+ mCurrentWidth = mWidth;
+ mCurrentHeight = mHeight;
+ }
+ invalidate();
+ } else {
+ animateToTarget(touching ? mCircleDiameter : mWidth,
+ touching ? mCircleDiameter : mHeight, touching);
+ }
+ }
+
+ private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
+ ObjectAnimator widthAnimator = ObjectAnimator.ofInt(this, WIDTH_PROPERTY,
+ mCurrentWidth, targetWidth);
+ ObjectAnimator heightAnimator = ObjectAnimator.ofInt(this, HEIGHT_PROPERTY,
+ mCurrentHeight, targetHeight);
+ mAnimator = new AnimatorSet();
+ mAnimator.playTogether(widthAnimator, heightAnimator);
+ mAnimator.setDuration(touching
+ ? DividerView.TOUCH_ANIMATION_DURATION
+ : DividerView.TOUCH_RELEASE_ANIMATION_DURATION);
+ mAnimator.setInterpolator(touching
+ ? DividerView.TOUCH_RESPONSE_INTERPOLATOR
+ : mFastOutSlowInInterpolator);
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimator = null;
+ }
+ });
+ mAnimator.start();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int left = getWidth() / 2 - mCurrentWidth / 2;
+ int top = getHeight() / 2 - mCurrentHeight / 2;
+ int radius = Math.min(mCurrentWidth, mCurrentHeight) / 2;
+ canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
+ radius, radius, mPaint);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
index 69e90cc..e43d531 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
@@ -17,25 +17,42 @@
package com.android.systemui.stackdivider;
import android.content.Context;
-import android.util.DisplayMetrics;
-import android.view.DisplayInfo;
+import android.graphics.Rect;
import com.android.systemui.statusbar.FlingAnimationUtils;
import java.util.ArrayList;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-
/**
* Calculates the snap targets and the snap position given a position and a velocity. All positions
* here are to be interpreted as the left/top edge of the divider rectangle.
*/
public class DividerSnapAlgorithm {
+ /**
+ * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
+ */
+ private static final int SNAP_MODE_16_9 = 0;
+
+ /**
+ * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+ */
+ private static final int SNAP_FIXED_RATIO = 1;
+
+ /**
+ * 1 snap target: 1:1
+ */
+ private static final int SNAP_ONLY_1_1 = 2;
+
private final Context mContext;
private final FlingAnimationUtils mFlingAnimationUtils;
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
private final int mDividerSize;
- private final ArrayList<SnapTarget> mTargets;
+ private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
+ private final Rect mInsets = new Rect();
+ private final int mSnapMode;
+ private final float mFixedRatio;
/** The first target which is still splitting the screen */
private final SnapTarget mFirstSplitTarget;
@@ -47,11 +64,19 @@
private final SnapTarget mDismissEndTarget;
public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
- int dividerSize, boolean isHorizontalDivision) {
+ int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
+ Rect insets) {
mContext = ctx;
mFlingAnimationUtils = flingAnimationUtils;
mDividerSize = dividerSize;
- mTargets = calculateTargets(isHorizontalDivision);
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mInsets.set(insets);
+ mSnapMode = ctx.getResources().getInteger(
+ com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+ mFixedRatio = ctx.getResources().getFraction(
+ com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
+ calculateTargets(isHorizontalDivision);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
@@ -75,6 +100,40 @@
}
}
+ public float calculateDismissingFraction(int position) {
+ if (position < mFirstSplitTarget.position) {
+ return 1f - (float) position / mFirstSplitTarget.position;
+ } else if (position > mLastSplitTarget.position) {
+ return (float) (position - mLastSplitTarget.position)
+ / (mDismissEndTarget.position - mLastSplitTarget.position);
+ }
+ return 0f;
+ }
+
+ public SnapTarget getClosestDismissTarget(int position) {
+ if (position - mDismissStartTarget.position < mDismissEndTarget.position - position) {
+ return mDismissStartTarget;
+ } else {
+ return mDismissEndTarget;
+ }
+ }
+
+ public SnapTarget getFirstSplitTarget() {
+ return mFirstSplitTarget;
+ }
+
+ public SnapTarget getLastSplitTarget() {
+ return mLastSplitTarget;
+ }
+
+ public SnapTarget getDismissStartTarget() {
+ return mDismissStartTarget;
+ }
+
+ public SnapTarget getDismissEndTarget() {
+ return mDismissEndTarget;
+ }
+
private SnapTarget snap(int position) {
int minIndex = -1;
int minDistance = Integer.MAX_VALUE;
@@ -89,22 +148,61 @@
return mTargets.get(minIndex);
}
- private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
- ArrayList<SnapTarget> targets = new ArrayList<>();
- DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+ private void calculateTargets(boolean isHorizontalDivision) {
+ mTargets.clear();
int dividerMax = isHorizontalDivision
- ? info.heightPixels
- : info.widthPixels;
+ ? mDisplayHeight
+ : mDisplayWidth;
+ mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+ switch (mSnapMode) {
+ case SNAP_MODE_16_9:
+ addRatio16_9Targets(isHorizontalDivision);
+ break;
+ case SNAP_FIXED_RATIO:
+ addFixedDivisionTargets(isHorizontalDivision);
+ break;
+ case SNAP_ONLY_1_1:
+ addMiddleTarget(isHorizontalDivision);
+ break;
+ }
+ mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+ }
- // TODO: Better calculation
- targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
- targets.add(new SnapTarget((int) (0.38f * dividerMax) - mDividerSize / 2,
+ private void addFixedDivisionTargets(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget((int) (0.62f * dividerMax) - mDividerSize / 2,
+ addMiddleTarget(isHorizontalDivision);
+ mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
+ - mDividerSize / 2, SnapTarget.FLAG_NONE));
+ }
+
+ private void addRatio16_9Targets(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
+ int endOther = isHorizontalDivision
+ ? mDisplayWidth - mInsets.right
+ : mDisplayHeight - mInsets.bottom;
+ float size = 9.0f / 16.0f * (endOther - startOther);
+ int sizeInt = (int) Math.floor(size);
+ mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
+ addMiddleTarget(isHorizontalDivision);
+ mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
+ }
+
+ private void addMiddleTarget(boolean isHorizontalDivision) {
+ int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+ int end = isHorizontalDivision
+ ? mDisplayHeight - mInsets.bottom
+ : mDisplayWidth - mInsets.right;
+ mTargets.add(new SnapTarget(start + (end - start) / 2 - mDividerSize / 2,
SnapTarget.FLAG_NONE));
- targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
- return targets;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index c01f170..109cf47 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,12 +21,14 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.MotionEvent;
@@ -34,8 +36,11 @@
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.Window;
+import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -56,15 +61,29 @@
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
+ static final long TOUCH_ANIMATION_DURATION = 150;
+ static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
+ static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+ new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
private static final String TAG = "DividerView";
- private ImageButton mHandle;
+ private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
+ private static final float DIM_START_FRACTION = 0.5f;
+ private static final float DIM_DAMP_FACTOR = 1.7f;
+
+ private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+ new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+ private DividerHandleView mHandle;
private View mBackground;
private int mStartX;
private int mStartY;
private int mStartPosition;
private int mDockSide;
private final int[] mTempInt2 = new int[2];
+ private boolean mMoving;
+ private int mTouchSlop;
private int mDividerInsets;
private int mDisplayWidth;
@@ -73,15 +92,20 @@
private int mDividerSize;
private int mTouchElevation;
- private final Rect mTmpRect = new Rect();
+ private final Rect mDockedRect = new Rect();
+ private final Rect mDockedTaskRect = new Rect();
+ private final Rect mOtherTaskRect = new Rect();
+ private final Rect mOtherRect = new Rect();
+ private final Rect mDockedInsetRect = new Rect();
+ private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
private Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mTouchResponseInterpolator =
- new PathInterpolator(0.3f, 0f, 0.1f, 1f);
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
+ private DividerSnapAlgorithm mSnapAlgorithm;
+ private final Rect mStableInsets = new Rect();
public DividerView(Context context) {
super(context);
@@ -103,7 +127,7 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mHandle = (ImageButton) findViewById(R.id.docked_divider_handle);
+ mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background);
mHandle.setOnTouchListener(this);
mDividerWindowWidth = getResources().getDimensionPixelSize(
@@ -115,6 +139,7 @@
R.dimen.docked_stack_divider_lift_elevation);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
+ mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
updateDisplayInfo();
boolean landscape = getResources().getConfiguration().orientation
@@ -124,6 +149,13 @@
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
}
+ @Override
+ public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+ mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+ insets.getStableInsetRight(), insets.getStableInsetBottom());
+ return super.onApplyWindowInsets(insets);
+ }
+
public void setWindowManager(DividerWindowManager windowManager) {
mWindowManager = windowManager;
}
@@ -132,8 +164,11 @@
return mWindowManagerProxy;
}
- public boolean startDragging() {
+ public boolean startDragging(boolean animate) {
+ mHandle.setTouching(true, animate);
mDockSide = mWindowManagerProxy.getDockSide();
+ mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils, mDisplayWidth,
+ mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
if (mDockSide != WindowManager.DOCKED_INVALID) {
mWindowManagerProxy.setResizing(true);
mWindowManager.setSlippery(false);
@@ -145,11 +180,16 @@
}
public void stopDragging(int position, float velocity) {
+ mHandle.setTouching(false, true /* animate */);
fling(position, velocity);
mWindowManager.setSlippery(true);
releaseBackground();
}
+ public DividerSnapAlgorithm getSnapAlgorithm() {
+ return mSnapAlgorithm;
+ }
+
@Override
public boolean onTouch(View v, MotionEvent event) {
convertToScreenCoordinates(event);
@@ -161,19 +201,31 @@
mStartX = (int) event.getX();
mStartY = (int) event.getY();
getLocationOnScreen(mTempInt2);
- boolean result = startDragging();
+ boolean result = startDragging(true /* animate */);
if (isHorizontalDivision()) {
mStartPosition = mTempInt2[1] + mDividerInsets;
} else {
mStartPosition = mTempInt2[0] + mDividerInsets;
}
+ mMoving = false;
return result;
case MotionEvent.ACTION_MOVE:
mVelocityTracker.addMovement(event);
int x = (int) event.getX();
int y = (int) event.getY();
- if (mDockSide != WindowManager.DOCKED_INVALID) {
- resizeStack(calculatePosition(x, y));
+ boolean exceededTouchSlop =
+ isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
+ || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
+ if (!mMoving && exceededTouchSlop) {
+ mStartX = x;
+ mStartY = y;
+ mMoving = true;
+ }
+ if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
+ int position = calculatePosition(x, y);
+ SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
+ 0 /* velocity */);
+ resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
}
break;
case MotionEvent.ACTION_UP:
@@ -187,6 +239,7 @@
int position = calculatePosition(x, y);
stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
: mVelocityTracker.getXVelocity());
+ mMoving = false;
break;
}
return true;
@@ -197,14 +250,16 @@
}
private void fling(int position, float velocity) {
- final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
- mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
+ final SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- resizeStack((Integer) animation.getAnimatedValue());
+ resizeStack((Integer) animation.getAnimatedValue(),
+ animation.getAnimatedFraction() == 1f
+ ? TASK_POSITION_SAME
+ : snapTarget.position, snapTarget);
}
});
anim.addListener(new AnimatorListenerAdapter() {
@@ -236,38 +291,43 @@
} else {
mWindowManagerProxy.maximizeDockedStack();
}
+ mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
}
private void liftBackground() {
if (isHorizontalDivision()) {
- mBackground.animate().scaleY(1.5f);
+ mBackground.animate().scaleY(1.4f);
} else {
- mBackground.animate().scaleX(1.5f);
+ mBackground.animate().scaleX(1.4f);
}
mBackground.animate()
- .setInterpolator(mTouchResponseInterpolator)
- .setDuration(150)
- .translationZ(mTouchElevation);
+ .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
// Lift handle as well so it doesn't get behind the background, even though it doesn't
// cast shadow.
mHandle.animate()
- .setInterpolator(mTouchResponseInterpolator)
- .setDuration(150)
- .translationZ(mTouchElevation);
+ .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+ .setDuration(TOUCH_ANIMATION_DURATION)
+ .translationZ(mTouchElevation)
+ .start();
}
private void releaseBackground() {
mBackground.animate()
.setInterpolator(mFastOutSlowInInterpolator)
- .setDuration(200)
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
.translationZ(0)
.scaleX(1f)
- .scaleY(1f);
+ .scaleY(1f)
+ .start();
mHandle.animate()
.setInterpolator(mFastOutSlowInInterpolator)
- .setDuration(200)
- .translationZ(0);
+ .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+ .translationZ(0)
+ .start();
}
@Override
@@ -332,17 +392,184 @@
}
}
- public void resizeStack(int position) {
- calculateBoundsForPosition(position, mDockSide, mTmpRect);
- if (mTmpRect.equals(mLastResizeRect)) {
+ private int invertDockSide(int dockSide) {
+ switch (dockSide) {
+ case WindowManager.DOCKED_LEFT:
+ return WindowManager.DOCKED_RIGHT;
+ case WindowManager.DOCKED_TOP:
+ return WindowManager.DOCKED_BOTTOM;
+ case WindowManager.DOCKED_RIGHT:
+ return WindowManager.DOCKED_LEFT;
+ case WindowManager.DOCKED_BOTTOM:
+ return WindowManager.DOCKED_TOP;
+ default:
+ return WindowManager.DOCKED_INVALID;
+ }
+ }
+
+ private void alignTopLeft(Rect containingRect, Rect rect) {
+ int width = rect.width();
+ int height = rect.height();
+ rect.set(containingRect.left, containingRect.top,
+ containingRect.left + width, containingRect.top + height);
+ }
+
+ private void alignBottomRight(Rect containingRect, Rect rect) {
+ int width = rect.width();
+ int height = rect.height();
+ rect.set(containingRect.right - width, containingRect.bottom - height,
+ containingRect.right, containingRect.bottom);
+ }
+
+ public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ calculateBoundsForPosition(position, mDockSide, mDockedRect);
+
+ if (mDockedRect.equals(mLastResizeRect)) {
return;
}
// Make sure shadows are updated
mBackground.invalidate();
- mLastResizeRect.set(mTmpRect);
- mWindowManagerProxy.resizeDockedStack(mTmpRect);
+ mLastResizeRect.set(mDockedRect);
+ if (taskPosition != TASK_POSITION_SAME) {
+ calculateBoundsForPosition(position, invertDockSide(mDockSide), mOtherRect);
+ int dockSideInverted = invertDockSide(mDockSide);
+ int taskPositionDocked =
+ restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
+ int taskPositionOther =
+ restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
+ calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
+ calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
+ alignTopLeft(mDockedRect, mDockedTaskRect);
+ alignTopLeft(mOtherRect, mOtherTaskRect);
+ mDockedInsetRect.set(mDockedTaskRect);
+ mOtherInsetRect.set(mOtherTaskRect);
+ if (dockSideTopLeft(mDockSide)) {
+ alignTopLeft(mDockedRect, mDockedInsetRect);
+ alignBottomRight(mOtherRect, mOtherInsetRect);
+ } else {
+ alignBottomRight(mDockedRect, mDockedInsetRect);
+ alignTopLeft(mOtherRect, mOtherInsetRect);
+ }
+ applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
+ taskPositionDocked);
+ applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
+ taskPositionOther);
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
+ mOtherTaskRect, mOtherInsetRect);
+ } else {
+ mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
+ }
+ float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
+ fraction = Math.max(0,
+ Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f));
+ mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
+ getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
+ fraction);
+ }
+
+ /**
+ * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
+ * 0 size.
+ */
+ private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
+ SnapTarget snapTarget) {
+ if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
+ return mSnapAlgorithm.getFirstSplitTarget().position;
+ } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+ && dockSideBottomRight(dockSide)) {
+ return mSnapAlgorithm.getLastSplitTarget().position;
+ } else {
+ return taskPosition;
+ }
+ }
+
+ /**
+ * Applies a parallax to the task when dismissing.
+ */
+ private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
+ int position, int taskPosition) {
+ float fraction = Math.min(1, Math.max(0,
+ mSnapAlgorithm.calculateDismissingFraction(position)));
+ SnapTarget dismissTarget = null;
+ SnapTarget splitTarget = null;
+ if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
+ || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+ && dockSideTopLeft(dockSide)) {
+ dismissTarget = mSnapAlgorithm.getDismissStartTarget();
+ splitTarget = mSnapAlgorithm.getFirstSplitTarget();
+ } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+ || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+ && dockSideBottomRight(dockSide)) {
+ dismissTarget = mSnapAlgorithm.getDismissEndTarget();
+ splitTarget = mSnapAlgorithm.getLastSplitTarget();
+ }
+ if (dismissTarget != null && fraction > 0f
+ && isDismissing(splitTarget, position, dockSide)) {
+ fraction = calculateParallaxDismissingFraction(fraction);
+ int offsetPosition = (int) (taskPosition +
+ fraction * (dismissTarget.position - splitTarget.position));
+ int width = taskRect.width();
+ int height = taskRect.height();
+ switch (dockSide) {
+ case WindowManager.DOCKED_LEFT:
+ taskRect.left = offsetPosition - width;
+ taskRect.right = offsetPosition;
+ break;
+ case WindowManager.DOCKED_RIGHT:
+ taskRect.left = offsetPosition + mDividerSize;
+ taskRect.right = offsetPosition + width + mDividerSize;
+ break;
+ case WindowManager.DOCKED_TOP:
+ taskRect.top = offsetPosition - height;
+ taskRect.bottom = offsetPosition;
+ break;
+ case WindowManager.DOCKED_BOTTOM:
+ taskRect.top = offsetPosition + mDividerSize;
+ taskRect.bottom = offsetPosition + height + mDividerSize;
+ break;
+ }
+ }
+ }
+
+ /**
+ * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+ * slowing down parallax effect
+ */
+ private static float calculateParallaxDismissingFraction(float fraction) {
+ return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+ }
+
+ private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
+ if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
+ return position < snapTarget.position;
+ } else {
+ return position > snapTarget.position;
+ }
+ }
+
+ private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
+ if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
+ (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+ return StackId.DOCKED_STACK_ID;
+ } else {
+ return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+ }
+ }
+
+ /**
+ * @return true if and only if {@code dockSide} is top or left
+ */
+ private static boolean dockSideTopLeft(int dockSide) {
+ return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
+ }
+
+ /**
+ * @return true if and only if {@code dockSide} is bottom or right
+ */
+ private static boolean dockSideBottomRight(int dockSide) {
+ return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2251874..161f873 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -50,6 +50,9 @@
| FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
mLp.setTitle(WINDOW_TITLE);
+ view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
mWindowManager.addView(view, mLp);
mView = view;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index ef47d8d..2791dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -40,18 +40,41 @@
private static final WindowManagerProxy sInstance = new WindowManagerProxy();
@GuardedBy("mResizeRect")
- private final Rect mResizeRect = new Rect();
- private final Rect mTmpRect = new Rect();
+ private final Rect mDockedRect = new Rect();
+ private final Rect mTempDockedTaskRect = new Rect();
+ private final Rect mTempDockedInsetRect = new Rect();
+ private final Rect mTempOtherTaskRect = new Rect();
+ private final Rect mTempOtherInsetRect = new Rect();
+
+ private final Rect mTmpRect1 = new Rect();
+ private final Rect mTmpRect2 = new Rect();
+ private final Rect mTmpRect3 = new Rect();
+ private final Rect mTmpRect4 = new Rect();
+ private final Rect mTmpRect5 = new Rect();
+
+ private boolean mDimLayerVisible;
+ private int mDimLayerTargetStack;
+ private float mDimLayerAlpha;
+
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private final Runnable mResizeRunnable = new Runnable() {
@Override
public void run() {
- synchronized (mResizeRect) {
- mTmpRect.set(mResizeRect);
+ synchronized (mDockedRect) {
+ mTmpRect1.set(mDockedRect);
+ mTmpRect2.set(mTempDockedTaskRect);
+ mTmpRect3.set(mTempDockedInsetRect);
+ mTmpRect4.set(mTempOtherTaskRect);
+ mTmpRect5.set(mTempOtherInsetRect);
}
try {
- ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, mTmpRect, true);
+ ActivityManagerNative.getDefault()
+ .resizeDockedStack(mTmpRect1,
+ mTmpRect2.isEmpty() ? null : mTmpRect2,
+ mTmpRect3.isEmpty() ? null : mTmpRect3,
+ mTmpRect4.isEmpty() ? null : mTmpRect4,
+ mTmpRect5.isEmpty() ? null : mTmpRect5);
} catch (RemoteException e) {
Log.w(TAG, "Failed to resize stack: " + e);
}
@@ -80,6 +103,18 @@
}
};
+ private final Runnable mDimLayerRunnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
+ mDimLayerTargetStack, mDimLayerAlpha);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to resize stack: " + e);
+ }
+ }
+ };
+
private WindowManagerProxy() {
}
@@ -87,9 +122,30 @@
return sInstance;
}
- public void resizeDockedStack(Rect rect) {
- synchronized (mResizeRect) {
- mResizeRect.set(rect);
+ public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
+ Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
+ synchronized (mDockedRect) {
+ mDockedRect.set(docked);
+ if (tempDockedTaskRect != null) {
+ mTempDockedTaskRect.set(tempDockedTaskRect);
+ } else {
+ mTempDockedTaskRect.setEmpty();
+ }
+ if (tempDockedInsetRect != null) {
+ mTempDockedInsetRect.set(tempDockedInsetRect);
+ } else {
+ mTempDockedInsetRect.setEmpty();
+ }
+ if (tempOtherTaskRect != null) {
+ mTempOtherTaskRect.set(tempOtherTaskRect);
+ } else {
+ mTempOtherTaskRect.setEmpty();
+ }
+ if (tempOtherInsetRect != null) {
+ mTempOtherInsetRect.set(tempOtherInsetRect);
+ } else {
+ mTempOtherInsetRect.setEmpty();
+ }
}
mExecutor.execute(mResizeRunnable);
}
@@ -123,4 +179,11 @@
}
return DOCKED_INVALID;
}
+
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ mDimLayerVisible = visible;
+ mDimLayerTargetStack = targetStackId;
+ mDimLayerAlpha = alpha;
+ mExecutor.execute(mDimLayerRunnable);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 39a33a5..fdfce6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
@@ -80,11 +78,8 @@
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
-import android.widget.DateTimeView;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RemoteViews;
-import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@@ -110,11 +105,13 @@
import com.android.systemui.statusbar.policy.PreviewInflater;
import com.android.systemui.statusbar.policy.RemoteInputView;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
public abstract class BaseStatusBar extends SystemUI implements
@@ -125,9 +122,6 @@
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean MULTIUSER_DEBUG = false;
- // STOPSHIP disable once we resolve b/18102199
- private static final boolean NOTIFICATION_CLICK_DEBUG = true;
-
public static final boolean ENABLE_REMOTE_INPUT =
SystemProperties.getBoolean("debug.enable_remote_input", true);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
@@ -140,15 +134,14 @@
protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
- protected static final int MSG_SHOW_KEYBOARD_SHORTCUTS_MENU = 1026;
+ protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
protected static final boolean ENABLE_HEADS_UP = true;
- // scores above this threshold should be displayed in heads up mode.
- protected static final int INTERRUPTION_THRESHOLD = 10;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- // Should match the value in PhoneWindowManager
+ // Should match the values in PhoneWindowManager
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+ public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
private static final String BANNER_ACTION_CANCEL =
"com.android.systemui.statusbar.banner_action_cancel";
@@ -165,6 +158,8 @@
protected NotificationGroupManager mGroupManager = new NotificationGroupManager();
+ protected RemoteInputController mRemoteInputController;
+
// for heads up notifications
protected HeadsUpManager mHeadsUpManager;
@@ -196,14 +191,10 @@
protected IDreamManager mDreamManager;
PowerManager mPowerManager;
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
- protected int mRowMinHeightLegacy;
- protected int mRowMinHeight;
- protected int mRowMaxHeight;
// public mode, private notifications, etc
private boolean mLockscreenPublicMode = false;
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
- private NotificationColorUtil mNotificationColorUtil;
private UserManager mUserManager;
@@ -233,6 +224,8 @@
private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn;
+ private KeyboardShortcuts mKeyboardShortcuts;
+
/**
* The {@link StatusBarState} of the status bar.
*/
@@ -353,9 +346,6 @@
ViewGroup actionGroup = (ViewGroup) parent;
index = actionGroup.indexOfChild(view);
}
- if (NOTIFICATION_CLICK_DEBUG) {
- Log.d(TAG, "Clicked on button " + index + " for " + key);
- }
try {
mBarService.onNotificationActionClick(key, index);
} catch (RemoteException e) {
@@ -613,8 +603,6 @@
mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
-
mNotificationData = new NotificationData(this);
mAccessibilityManager = (AccessibilityManager)
@@ -945,7 +933,7 @@
final StatusBarNotification sbn = row.getStatusBarNotification();
PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
row.setTag(sbn.getPackageName());
- final View guts = row.getGuts();
+ final NotificationGuts guts = row.getGuts();
final String pkg = sbn.getPackageName();
String appname = pkg;
Drawable pkgicon = null;
@@ -967,9 +955,7 @@
((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
((TextView) row.findViewById(R.id.pkgname)).setText(appname);
- bindTopicImportance(sbn, row);
-
- final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+ final View settingsButton = guts.findViewById(R.id.more_settings);
if (appUid >= 0) {
final int appUidF = appUid;
settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -981,77 +967,22 @@
} else {
settingsButton.setVisibility(View.GONE);
}
- }
- private void bindTopicImportance(final StatusBarNotification sbn,
- ExpandableNotificationRow row) {
- final INotificationManager sINM = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- final Notification.Topic topic = sbn.getNotification().getTopic() == null
- ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
- com.android.internal.R.string.default_notification_topic_label))
- : sbn.getNotification().getTopic();
-
- ((TextView) row.findViewById(R.id.topic_details)).setText(topic.getLabel());
- final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
- int importance = mNotificationData.getImportance(sbn.getKey());
- SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar);
- seekBar.setMax(4);
- seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
@Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- topicSummary.setText(getProgressSummary(progress));
- if (fromUser) {
- try {
- sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic,
- progress);
- } catch (RemoteException e) {
- // :(
- }
- }
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- // no-op
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- // no-op
- }
-
- private String getProgressSummary(int progress) {
- switch (progress) {
- case NotificationListenerService.Ranking.IMPORTANCE_NONE:
- return mContext.getString(
- com.android.internal.R.string.notification_importance_blocked);
- case NotificationListenerService.Ranking.IMPORTANCE_LOW:
- return mContext.getString(
- com.android.internal.R.string.notification_importance_low);
- case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
- return mContext.getString(
- com.android.internal.R.string.notification_importance_default);
- case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
- return mContext.getString(
- com.android.internal.R.string.notification_importance_high);
- case NotificationListenerService.Ranking.IMPORTANCE_MAX:
- return mContext.getString(
- com.android.internal.R.string.notification_importance_max);
- default:
- return "";
- }
+ public void onClick(View v) {
+ guts.saveImportance(sbn);
+ dismissPopups();
}
});
- seekBar.setProgress(importance);
+
+ guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
}
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
- public boolean onLongPress(View v, int x, int y) {
- dismissPopups();
-
+ public boolean onLongPress(View v, final int x, final int y) {
if (!(v instanceof ExpandableNotificationRow)) {
return false;
}
@@ -1072,41 +1003,57 @@
// Already showing?
if (guts.getVisibility() == View.VISIBLE) {
- Log.e(TAG, "Trying to show notification guts, but already visible");
+ dismissPopups(x, y);
return false;
}
MetricsLogger.action(mContext, MetricsLogger.ACTION_NOTE_CONTROLS);
- guts.setVisibility(View.VISIBLE);
- final double horz = Math.max(guts.getWidth() - x, x);
- final double vert = Math.max(guts.getActualHeight() - y, y);
- final float r = (float) Math.hypot(horz, vert);
- final Animator a
- = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
- a.setDuration(400);
- a.setInterpolator(mLinearOutSlowIn);
- a.start();
-
- mNotificationGutsExposed = guts;
-
+ // ensure that it's layouted but not visible until actually laid out
+ guts.setVisibility(View.INVISIBLE);
+ // Post to ensure the the guts are properly layed out.
+ guts.post(new Runnable() {
+ public void run() {
+ dismissPopups();
+ guts.setVisibility(View.VISIBLE);
+ final double horz = Math.max(guts.getWidth() - x, x);
+ final double vert = Math.max(guts.getHeight() - y, y);
+ final float r = (float) Math.hypot(horz, vert);
+ final Animator a
+ = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ a.setInterpolator(mLinearOutSlowIn);
+ a.start();
+ guts.setExposed(true);
+ mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+ mNotificationGutsExposed = guts;
+ }
+ });
return true;
}
};
}
public void dismissPopups() {
+ dismissPopups(-1, -1);
+ }
+
+ private void dismissPopups(int x, int y) {
if (mNotificationGutsExposed != null) {
final NotificationGuts v = mNotificationGutsExposed;
mNotificationGutsExposed = null;
if (v.getWindowToken() == null) return;
-
- final int x = (v.getLeft() + v.getRight()) / 2;
- final int y = (v.getTop() + v.getActualHeight() / 2);
+ if (x == -1 || y == -1) {
+ x = (v.getLeft() + v.getRight()) / 2;
+ y = (v.getTop() + v.getHeight() / 2);
+ }
+ final double horz = Math.max(v.getWidth() - x, x);
+ final double vert = Math.max(v.getHeight() - y, y);
+ final float r = (float) Math.hypot(horz, vert);
final Animator a = ViewAnimationUtils.createCircularReveal(v,
- x, y, x, 0);
- a.setDuration(200);
+ x, y, r, 0);
+ a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
a.setInterpolator(mFastOutLinearIn);
a.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1116,6 +1063,8 @@
}
});
a.start();
+ v.setExposed(false);
+ mStackScroller.onHeightChanged(null, true /* needsAnimation */);
}
}
@@ -1154,8 +1103,8 @@
}
@Override
- public void showKeyboardShortcutsMenu() {
- int msg = MSG_SHOW_KEYBOARD_SHORTCUTS_MENU;
+ public void toggleKeyboardShortcutsMenu() {
+ int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
mHandler.removeMessages(msg);
mHandler.sendEmptyMessage(msg);
}
@@ -1178,7 +1127,7 @@
return new H();
}
- static void sendCloseSystemWindows(Context context, String reason) {
+ protected void sendCloseSystemWindows(String reason) {
if (ActivityManagerNative.isSystemReady()) {
try {
ActivityManagerNative.getDefault().closeSystemDialogs(reason);
@@ -1213,7 +1162,7 @@
protected void showRecents(boolean triggeredFromAltTab) {
if (mRecents != null) {
- sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
+ sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
mRecents.showRecents(triggeredFromAltTab, getStatusBarView());
}
}
@@ -1226,7 +1175,6 @@
protected void toggleRecents() {
if (mRecents != null) {
- sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
}
}
@@ -1237,8 +1185,8 @@
}
}
- protected void showKeyboardShortcuts() {
- Toast.makeText(mContext, "Show keyboard shortcuts screen", Toast.LENGTH_LONG).show();
+ protected void toggleKeyboardShortcuts() {
+ getKeyboardShortcuts().toggleKeyboardShortcuts(mContext);
}
protected void cancelPreloadingRecents() {
@@ -1361,8 +1309,8 @@
case MSG_SHOW_PREV_AFFILIATED_TASK:
showRecentsPreviousAffiliatedTask();
break;
- case MSG_SHOW_KEYBOARD_SHORTCUTS_MENU:
- showKeyboardShortcuts();
+ case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
+ toggleKeyboardShortcuts();
break;
}
}
@@ -1417,6 +1365,7 @@
parent, false);
row.setExpansionLogger(this, entry.notification.getKey());
row.setGroupManager(mGroupManager);
+ row.setRemoteInputController(mRemoteInputController);
row.setOnExpandClickListener(this);
}
@@ -1442,6 +1391,7 @@
View contentViewLocal = null;
View bigContentViewLocal = null;
View headsUpContentViewLocal = null;
+ View publicViewLocal = null;
try {
contentViewLocal = contentView.apply(
sbn.getPackageContext(mContext),
@@ -1459,6 +1409,11 @@
contentContainer,
mOnClickHandler);
}
+ if (publicContentView != null) {
+ publicViewLocal = publicContentView.apply(
+ sbn.getPackageContext(mContext),
+ contentContainerPublic, mOnClickHandler);
+ }
}
catch (RuntimeException e) {
final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -1478,25 +1433,9 @@
headsUpContentViewLocal.setIsRootNamespace(true);
contentContainer.setHeadsUpChild(headsUpContentViewLocal);
}
-
- // now the public version
- View publicViewLocal = null;
- if (publicContentView != null) {
- try {
- publicViewLocal = publicContentView.apply(
- sbn.getPackageContext(mContext),
- contentContainerPublic, mOnClickHandler);
-
- if (publicViewLocal != null) {
- publicViewLocal.setIsRootNamespace(true);
- contentContainerPublic.setContractedChild(publicViewLocal);
- }
- }
- catch (RuntimeException e) {
- final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
- Log.e(TAG, "couldn't inflate public view for notification " + ident, e);
- publicViewLocal = null;
- }
+ if (publicViewLocal != null) {
+ publicViewLocal.setIsRootNamespace(true);
+ contentContainerPublic.setContractedChild(publicViewLocal);
}
// Extract target SDK version.
@@ -1506,65 +1445,7 @@
} catch (NameNotFoundException ex) {
Log.e(TAG, "Failed looking up ApplicationInfo for " + sbn.getPackageName(), ex);
}
-
- if (publicViewLocal == null) {
- // Add a basic notification template
- publicViewLocal = LayoutInflater.from(mContext).inflate(
- R.layout.notification_public_default,
- contentContainerPublic, false);
- publicViewLocal.setIsRootNamespace(true);
-
- final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
- try {
- title.setText(pmUser.getApplicationLabel(
- pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
- } catch (NameNotFoundException e) {
- title.setText(entry.notification.getPackageName());
- }
-
- final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
- final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
- R.id.profile_badge_line3);
-
- final StatusBarIcon ic = new StatusBarIcon(
- entry.notification.getUser(),
- entry.notification.getPackageName(),
- entry.notification.getNotification().getSmallIcon(),
- entry.notification.getNotification().iconLevel,
- entry.notification.getNotification().number,
- entry.notification.getNotification().tickerText);
-
- Drawable iconDrawable = StatusBarIconView.getIcon(mContext, ic);
- icon.setImageDrawable(iconDrawable);
-
- if (profileBadge != null) {
- Drawable profileDrawable = mContext.getPackageManager().getUserBadgeForDensity(
- entry.notification.getUser(), 0);
- if (profileDrawable != null) {
- profileBadge.setImageDrawable(profileDrawable);
- profileBadge.setVisibility(View.VISIBLE);
- } else {
- profileBadge.setVisibility(View.GONE);
- }
- }
-
- final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
- final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
- if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
- time.setVisibility(View.VISIBLE);
- time.setTime(entry.notification.getNotification().when);
- }
-
- final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
- if (text != null) {
- text.setText(R.string.notification_hidden_text);
- text.setTextAppearance(mContext,
- R.style.TextAppearance_Material_Notification_Parenthetical);
- }
-
- contentContainerPublic.setContractedChild(publicViewLocal);
- entry.autoRedacted = true;
- }
+ entry.autoRedacted = entry.notification.getNotification().publicVersion == null;
if (MULTIUSER_DEBUG) {
TextView debug = (TextView) row.findViewById(R.id.debug_info);
@@ -1587,7 +1468,6 @@
}
row.setUserLocked(userLocked);
row.onNotificationUpdated(entry);
- applyRemoteInput(entry);
return true;
}
@@ -1610,8 +1490,14 @@
for (int i = 0; i < numActions; i++) {
Notification.Action action = actions.get(i);
+ if (action == null) {
+ continue;
+ }
RemoteInput[] remoteInputs = action.getRemoteInputs();
- for (RemoteInput ri : action.getRemoteInputs()) {
+ if (remoteInputs == null) {
+ continue;
+ }
+ for (RemoteInput ri : remoteInputs) {
if (ri.getAllowFreeFormInput()) {
viableAction = action;
break;
@@ -1630,76 +1516,12 @@
}
}
- private void applyRemoteInput(final Entry entry) {
- if (!ENABLE_REMOTE_INPUT) return;
-
- boolean hasRemoteInput = false;
-
- Notification.Action[] actions = entry.notification.getNotification().actions;
- if (actions != null) {
- for (Notification.Action a : actions) {
- if (a.getRemoteInputs() != null) {
- for (RemoteInput ri : a.getRemoteInputs()) {
- if (ri.getAllowFreeFormInput()) {
- hasRemoteInput = true;
- break;
- }
- }
- }
- }
+ protected KeyboardShortcuts getKeyboardShortcuts() {
+ if (mKeyboardShortcuts == null) {
+ mKeyboardShortcuts = new KeyboardShortcuts();
}
- View bigContentView = entry.getExpandedContentView();
- if (bigContentView != null) {
- applyRemoteInput(bigContentView, entry, hasRemoteInput);
- }
- View headsUpContentView = entry.getHeadsUpContentView();
- if (headsUpContentView != null) {
- applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
- }
-
- }
-
- private RemoteInputView applyRemoteInput(View view, Entry entry, boolean hasRemoteInput) {
- View actionContainerCandidate = view.findViewById(
- com.android.internal.R.id.actions_container);
- if (actionContainerCandidate instanceof FrameLayout) {
- RemoteInputView existing = (RemoteInputView)
- view.findViewWithTag(RemoteInputView.VIEW_TAG);
-
- if (hasRemoteInput) {
- if (existing != null) {
- existing.onNotificationUpdate();
- return existing;
- }
-
- ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
- RemoteInputView riv = inflateRemoteInputView(actionContainer, entry);
- if (riv != null) {
- riv.setVisibility(View.INVISIBLE);
- actionContainer.addView(riv, new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT)
- );
- int color = entry.notification.getNotification().color;
- if (color == Notification.COLOR_DEFAULT) {
- color = mContext.getColor(R.color.default_remote_input_background);
- }
- riv.setBackgroundColor(color);
- return riv;
- }
- } else {
- if (existing != null) {
- existing.onNotificationUpdate();
- return null;
- }
- }
- }
- return null;
- }
-
- protected RemoteInputView inflateRemoteInputView(ViewGroup root, Entry entry) {
- return null;
+ return mKeyboardShortcuts;
}
public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
@@ -1784,9 +1606,6 @@
}
});
- if (NOTIFICATION_CLICK_DEBUG) {
- Log.d(TAG, "Clicked on content of " + notificationKey);
- }
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
final boolean afterKeyguardGone = intent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(),
@@ -2168,7 +1987,8 @@
}
catch (RuntimeException e) {
// It failed to apply cleanly.
- Log.w(TAG, "Couldn't reapply views for package " + n.contentView.getPackage(), e);
+ Log.w(TAG, "Couldn't reapply views for package " +
+ notification.getPackageName(), e);
}
}
if (!updateSuccessful) {
@@ -2230,8 +2050,6 @@
entry.row.onNotificationUpdated(entry);
entry.row.resetHeight();
-
- applyRemoteInput(entry);
}
protected void notifyHeadsUpScreenOff() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index deedae0..5a2758d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -65,7 +65,7 @@
private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT;
private static final int MSG_START_ASSIST = 23 << MSG_SHIFT;
private static final int MSG_CAMERA_LAUNCH_GESTURE = 24 << MSG_SHIFT;
- private static final int MSG_SHOW_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT;
+ private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -100,7 +100,7 @@
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
public void toggleRecentApps();
public void preloadRecentApps();
- public void showKeyboardShortcutsMenu();
+ public void toggleKeyboardShortcutsMenu();
public void cancelPreloadRecentApps();
public void setWindowState(int window, int state);
public void buzzBeepBlinked();
@@ -229,10 +229,10 @@
}
@Override
- public void showKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu() {
synchronized (mList) {
- mHandler.removeMessages(MSG_SHOW_KEYBOARD_SHORTCUTS);
- mHandler.obtainMessage(MSG_SHOW_KEYBOARD_SHORTCUTS).sendToTarget();
+ mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS);
+ mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS).sendToTarget();
}
}
@@ -380,8 +380,8 @@
case MSG_CANCEL_PRELOAD_RECENT_APPS:
mCallbacks.cancelPreloadRecentApps();
break;
- case MSG_SHOW_KEYBOARD_SHORTCUTS:
- mCallbacks.showKeyboardShortcutsMenu();
+ case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
+ mCallbacks.toggleKeyboardShortcutsMenu();
break;
case MSG_SET_WINDOW_STATE:
mCallbacks.setWindowState(msg.arg1, msg.arg2);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index ed4c774..83853a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -25,12 +25,10 @@
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.LinearInterpolator;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -49,13 +47,11 @@
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
- private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
private final int mNotificationMinHeightLegacy;
private final int mMaxHeadsUpHeightLegacy;
private final int mMaxHeadsUpHeight;
private final int mNotificationMinHeight;
private final int mNotificationMaxHeight;
- private int mRowMinHeight;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -117,7 +113,7 @@
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
- if (mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
+ if (!mShowingPublic && mGroupManager.isSummaryOfGroup(mStatusBarNotification)) {
mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(ExpandableNotificationRow.this,
mGroupManager.isGroupExpanded(mStatusBarNotification));
@@ -199,8 +195,8 @@
public void onNotificationUpdated(NotificationData.Entry entry) {
mEntry = entry;
mStatusBarNotification = entry.notification;
- mPrivateLayout.onNotificationUpdated(entry.notification);
- mPublicLayout.onNotificationUpdated(entry.notification);
+ mPrivateLayout.onNotificationUpdated(entry);
+ mPublicLayout.onNotificationUpdated(entry);
updateVetoButton();
if (mIsSummaryWithChildren) {
recreateNotificationHeader();
@@ -212,6 +208,8 @@
mNotificationParent.updateChildrenHeaderAppearance();
}
onChildrenCountChanged();
+ // The public layouts expand button is always visible
+ mPublicLayout.updateExpandButtons(true);
updateLimits();
}
@@ -226,10 +224,9 @@
!= com.android.internal.R.id.status_bar_latest_event_content;
int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
: mMaxHeadsUpHeight;
- mRowMinHeight = minHeight;
mMaxViewHeight = mNotificationMaxHeight;
- mPrivateLayout.setHeights(mRowMinHeight, headsUpheight);
- mPublicLayout.setHeights(mRowMinHeight, headsUpheight);
+ mPrivateLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+ mPublicLayout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
}
public StatusBarNotification getStatusBarNotification() {
@@ -254,6 +251,10 @@
mPrivateLayout.setGroupManager(groupManager);
}
+ public void setRemoteInputController(RemoteInputController r) {
+ mPrivateLayout.setRemoteInputController(r);
+ }
+
public void addChildNotification(ExpandableNotificationRow row) {
addChildNotification(row, -1);
}
@@ -485,7 +486,6 @@
@Override
public void reset() {
super.reset();
- mRowMinHeight = 0;
final boolean wasExpanded = isExpanded();
mMaxViewHeight = 0;
mExpandable = false;
@@ -514,11 +514,6 @@
}
@Override
- protected boolean filterMotionEvent(MotionEvent event) {
- return mIsHeadsUp || super.filterMotionEvent(event);
- }
-
- @Override
protected void onFinishInflate() {
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
@@ -554,12 +549,15 @@
}
private void updateChildrenVisibility() {
+ mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? VISIBLE
+ : INVISIBLE);
if (mChildrenContainer == null) {
return;
}
- mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
- mNotificationHeader.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
- mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
+ mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
+ : INVISIBLE);
+ mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
+ : INVISIBLE);
// The limits might have changed if the view suddenly became a group or vice versa
updateLimits();
}
@@ -711,7 +709,7 @@
if (expand && mExpandable) {
setActualHeight(mMaxExpandHeight);
} else {
- setActualHeight(mRowMinHeight);
+ setActualHeight(getMinHeight());
}
}
@@ -721,20 +719,24 @@
return getActualHeight();
}
boolean inExpansionState = isExpanded();
- if (mSensitive && mHideSensitiveForIntrinsicHeight) {
- return mRowMinHeight;
+ if (mGuts != null && mGuts.areGutsExposed()) {
+ return mGuts.getHeight();
+ } else if ((isChildInGroup() && !isGroupExpanded())) {
+ return mPrivateLayout.getMinHeight();
+ } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
+ return getMinHeight();
} else if (mIsSummaryWithChildren && !mOnKeyguard) {
return mChildrenContainer.getIntrinsicHeight();
} else if (mIsHeadsUp) {
if (inExpansionState) {
- return Math.max(mMaxExpandHeight, mHeadsUpHeight);
+ return Math.max(getMaxExpandHeight(), mHeadsUpHeight);
} else {
- return Math.max(mRowMinHeight, mHeadsUpHeight);
+ return Math.max(getMinHeight(), mHeadsUpHeight);
}
- } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
- return getMinHeight();
- } else {
+ } else if (inExpansionState) {
return getMaxExpandHeight();
+ } else {
+ return getMinHeight();
}
}
@@ -841,8 +843,7 @@
mPublicLayout.setAlpha(1f);
mPrivateLayout.setAlpha(1f);
mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
- mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
- : View.INVISIBLE);
+ updateChildrenVisibility();
} else {
animateShowingPublic(delay, duration);
}
@@ -853,27 +854,35 @@
}
private void animateShowingPublic(long delay, long duration) {
- final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
- View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
- source.setVisibility(View.VISIBLE);
- target.setVisibility(View.VISIBLE);
- target.setAlpha(0f);
- source.animate().cancel();
- target.animate().cancel();
- source.animate()
- .alpha(0f)
- .setStartDelay(delay)
- .setDuration(duration)
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- source.setVisibility(View.INVISIBLE);
- }
- });
- target.animate()
- .alpha(1f)
- .setStartDelay(delay)
- .setDuration(duration);
+ View[] privateViews = mIsSummaryWithChildren ?
+ new View[] {mChildrenContainer, mNotificationHeader}
+ : new View[] {mPrivateLayout};
+ View[] publicViews = new View[] {mPublicLayout};
+ View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
+ View[] shownChildren = mShowingPublic ? publicViews : privateViews;
+ for (final View hiddenView : hiddenChildren) {
+ hiddenView.setVisibility(View.VISIBLE);
+ hiddenView.animate().cancel();
+ hiddenView.animate()
+ .alpha(0f)
+ .setStartDelay(delay)
+ .setDuration(duration)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ hiddenView.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ for (View showView : shownChildren) {
+ showView.setVisibility(View.VISIBLE);
+ showView.setAlpha(0f);
+ showView.animate().cancel();
+ showView.animate()
+ .alpha(1f)
+ .setStartDelay(delay)
+ .setDuration(duration);
+ }
}
private void updateVetoButton() {
@@ -952,6 +961,9 @@
@Override
public int getMinHeight() {
+ if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
+ return mChildrenContainer.getMinHeight();
+ }
NotificationContentView showingLayout = getShowingLayout();
return showingLayout.getMinHeight();
}
@@ -959,17 +971,12 @@
@Override
public int getMinExpandHeight() {
if (mIsSummaryWithChildren && !mOnKeyguard) {
- return mChildrenContainer.getMinHeight();
+ return mChildrenContainer.getMinExpandHeight();
}
return getMinHeight();
}
@Override
- protected boolean shouldLimitViewHeight() {
- return !mIsSummaryWithChildren;
- }
-
- @Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
mPrivateLayout.setClipTopAmount(clipTopAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 59cbd40..d6855a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -20,10 +20,10 @@
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+
import com.android.systemui.R;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -45,7 +45,6 @@
private static Rect mClipRect = new Rect();
private boolean mWillBeGone;
private int mMinClipTopAmount = 0;
- private boolean mMeasuredTooHigh;
public ExpandableView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -55,13 +54,10 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- boolean limitViewHeight = shouldLimitViewHeight();
final int givenSize = MeasureSpec.getSize(heightMeasureSpec);
- int ownMaxHeight = limitViewHeight ? mMaxViewHeight : Integer.MAX_VALUE;
+ int ownMaxHeight = Integer.MAX_VALUE;
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
- if (hasFixedHeight) {
- // We have a height set in our layout, so we want to be at most as big as given
+ if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) {
ownMaxHeight = Math.min(givenSize, ownMaxHeight);
}
int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
@@ -77,7 +73,7 @@
if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
if (layoutParams.height >= 0) {
// An actual height is set
- childHeightSpec = layoutParams.height > ownMaxHeight && limitViewHeight
+ childHeightSpec = layoutParams.height > ownMaxHeight
? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
: MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
}
@@ -90,7 +86,8 @@
mMatchParentViews.add(child);
}
}
- int ownHeight = hasFixedHeight ? ownMaxHeight : Math.min(ownMaxHeight, maxChildHeight);
+ int ownHeight = heightMode == MeasureSpec.EXACTLY
+ ? givenSize : Math.min(ownMaxHeight, maxChildHeight);
newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY);
for (View child : mMatchParentViews) {
child.measure(getChildMeasureSpec(
@@ -100,11 +97,6 @@
mMatchParentViews.clear();
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, ownHeight);
- mMeasuredTooHigh = heightMode != MeasureSpec.UNSPECIFIED && ownHeight > givenSize;
- }
-
- protected boolean shouldLimitViewHeight() {
- return true;
}
@Override
@@ -133,26 +125,11 @@
}
@Override
- public boolean dispatchGenericMotionEvent(MotionEvent ev) {
- if (filterMotionEvent(ev)) {
- return super.dispatchGenericMotionEvent(ev);
- }
- return false;
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- if (filterMotionEvent(ev)) {
- return super.dispatchTouchEvent(ev);
- }
- return false;
- }
-
- protected boolean filterMotionEvent(MotionEvent event) {
- return event.getActionMasked() != MotionEvent.ACTION_DOWN
- && event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER
- && event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE
- || event.getY() > mClipTopAmount && event.getY() < mActualHeight;
+ public boolean pointInView(float localX, float localY, float slop) {
+ float top = mClipTopAmount;
+ float bottom = mActualHeight;
+ return localX >= -slop && localY >= top - slop && localX < ((mRight - mLeft) + slop) &&
+ localY < (bottom + slop);
}
/**
@@ -397,7 +374,8 @@
@Override
public boolean hasOverlappingRendering() {
- return super.hasOverlappingRendering() && !mMeasuredTooHigh;
+ // Otherwise it will be clipped
+ return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
new file mode 100644
index 0000000..3e0ea90
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+
+/**
+ * Contains functionality for handling keyboard shortcuts.
+ */
+public class KeyboardShortcuts {
+ private Dialog mKeyboardShortcutsDialog;
+
+ public KeyboardShortcuts() {}
+
+ public void toggleKeyboardShortcuts(Context context) {
+ if (mKeyboardShortcutsDialog == null) {
+ // Create dialog.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
+ LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ final View keyboardShortcutsView = inflater.inflate(
+ R.layout.keyboard_shortcuts_view, null);
+
+ populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
+ R.id.keyboard_shortcuts_wrapper));
+ dialogBuilder.setView(keyboardShortcutsView);
+ mKeyboardShortcutsDialog = dialogBuilder.create();
+ mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+ // Setup window.
+ Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+ keyboardShortcutsWindow.setType(
+ WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+ keyboardShortcutsWindow.setBackgroundDrawable(
+ new ColorDrawable(android.graphics.Color.TRANSPARENT));
+ keyboardShortcutsWindow.setGravity(Gravity.TOP);
+ mKeyboardShortcutsDialog.show();
+ } else {
+ dismissKeyboardShortcutsDialog();
+ }
+ }
+
+ public void dismissKeyboardShortcutsDialog() {
+ if (mKeyboardShortcutsDialog != null) {
+ mKeyboardShortcutsDialog.dismiss();
+ mKeyboardShortcutsDialog = null;
+ }
+ }
+
+ /**
+ * @return {@code true} if the keyboard shortcuts have been successfully populated.
+ */
+ private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) {
+ // TODO: Populate shortcuts.
+ return true;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 2944c4f4..02a39e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -16,12 +16,15 @@
package com.android.systemui.statusbar;
+import android.app.Notification;
+import android.app.RemoteInput;
import android.content.Context;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.NotificationHeaderView;
@@ -37,6 +40,7 @@
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.policy.RemoteInputView;
/**
* A frame layout containing the actual payload of the notification, including the contracted,
@@ -55,6 +59,8 @@
private final int mRoundRectRadius;
private final Interpolator mLinearInterpolator = new LinearInterpolator();
private final boolean mRoundRectClippingEnabled;
+ private final int mMinContractedHeight;
+
private View mContractedChild;
private View mExpandedChild;
@@ -77,8 +83,10 @@
private boolean mIsChildInGroup;
private int mSmallHeight;
private int mHeadsUpHeight;
+ private int mNotificationMaxHeight;
private StatusBarNotification mStatusBarNotification;
private NotificationGroupManager mGroupManager;
+ private RemoteInputController mRemoteInputController;
private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
= new ViewTreeObserver.OnPreDrawListener() {
@@ -98,6 +106,8 @@
}
};
private OnClickListener mExpandClickListener;
+ private boolean mBeforeN;
+ private boolean mExpandable;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -107,13 +117,16 @@
R.dimen.notification_material_rounded_rect_radius);
mRoundRectClippingEnabled = getResources().getBoolean(
R.bool.config_notifications_round_rect_clipping);
+ mMinContractedHeight = getResources().getDimensionPixelSize(
+ R.dimen.min_notification_layout_height);
reset(true);
setOutlineProvider(mOutlineProvider);
}
- public void setHeights(int smallHeight, int headsUpMaxHeight) {
+ public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
mSmallHeight = smallHeight;
mHeadsUpHeight = headsUpMaxHeight;
+ mNotificationMaxHeight = maxHeight;
}
@Override
@@ -127,13 +140,23 @@
}
int maxChildHeight = 0;
if (mContractedChild != null) {
- int size = Math.min(maxSize, mSmallHeight);
- mContractedChild.measure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
- maxChildHeight = Math.max(maxChildHeight, mContractedChild.getMeasuredHeight());
+ int heightSpec;
+ if (shouldContractedBeFixedSize()) {
+ int size = Math.min(maxSize, mSmallHeight);
+ heightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+ } else {
+ heightSpec = MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST);
+ }
+ mContractedChild.measure(widthMeasureSpec, heightSpec);
+ int measuredHeight = mContractedChild.getMeasuredHeight();
+ if (measuredHeight < mMinContractedHeight) {
+ heightSpec = MeasureSpec.makeMeasureSpec(mMinContractedHeight, MeasureSpec.EXACTLY);
+ mContractedChild.measure(widthMeasureSpec, heightSpec);
+ }
+ maxChildHeight = Math.max(maxChildHeight, measuredHeight);
}
if (mExpandedChild != null) {
- int size = maxSize;
+ int size = Math.min(maxSize, mNotificationMaxHeight);
ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
if (layoutParams.height >= 0) {
// An actual height is set
@@ -166,6 +189,10 @@
setMeasuredDimension(width, ownHeight);
}
+ private boolean shouldContractedBeFixedSize() {
+ return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -288,14 +315,14 @@
} else if (mIsHeadsUp && mHeadsUpChild != null) {
return mHeadsUpChild.getHeight();
}
- return mSmallHeight;
+ return mContractedChild.getHeight();
}
public int getMinHeight() {
if (mIsChildInGroup && !isGroupExpanded()) {
return mSingleLineView.getHeight();
} else {
- return mSmallHeight;
+ return mContractedChild.getHeight();
}
}
@@ -431,6 +458,9 @@
if (!noExpandedChild && mContentHeight == mExpandedChild.getHeight()) {
return VISIBLE_TYPE_EXPANDED;
}
+ if (mIsChildInGroup && !isGroupExpanded()) {
+ return VISIBLE_TYPE_SINGLELINE;
+ }
if (mIsHeadsUp && mHeadsUpChild != null) {
if (mContentHeight <= mHeadsUpChild.getHeight() || noExpandedChild) {
@@ -439,9 +469,7 @@
return VISIBLE_TYPE_EXPANDED;
}
} else {
- if (mIsChildInGroup && !isGroupExpanded()) {
- return VISIBLE_TYPE_SINGLELINE;
- } else if (mContentHeight <= mSmallHeight || noExpandedChild) {
+ if (mContentHeight <= mContractedChild.getHeight() || noExpandedChild) {
return VISIBLE_TYPE_CONTRACTED;
} else {
return VISIBLE_TYPE_EXPANDED;
@@ -465,6 +493,7 @@
public void setHeadsUp(boolean headsUp) {
mIsHeadsUp = headsUp;
selectLayout(false /* animate */, true /* force */);
+ updateExpandButtons(mExpandable);
}
@Override
@@ -484,9 +513,11 @@
updateSingleLineView();
}
- public void onNotificationUpdated(StatusBarNotification statusBarNotification) {
- mStatusBarNotification = statusBarNotification;
+ public void onNotificationUpdated(NotificationData.Entry entry) {
+ mStatusBarNotification = entry.notification;
+ mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
updateSingleLineView();
+ applyRemoteInput(entry);
selectLayout(false /* animate */, true /* force */);
if (mContractedChild != null) {
mContractedWrapper.notifyContentUpdated();
@@ -508,15 +539,87 @@
}
}
+ private void applyRemoteInput(final NotificationData.Entry entry) {
+ if (mRemoteInputController == null) {
+ return;
+ }
+
+ boolean hasRemoteInput = false;
+
+ Notification.Action[] actions = entry.notification.getNotification().actions;
+ if (actions != null) {
+ for (Notification.Action a : actions) {
+ if (a.getRemoteInputs() != null) {
+ for (RemoteInput ri : a.getRemoteInputs()) {
+ if (ri.getAllowFreeFormInput()) {
+ hasRemoteInput = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ View bigContentView = mExpandedChild;
+ if (bigContentView != null) {
+ applyRemoteInput(bigContentView, entry, hasRemoteInput);
+ }
+ View headsUpContentView = mHeadsUpChild;
+ if (headsUpContentView != null) {
+ applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+ }
+ }
+
+ private void applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+ View actionContainerCandidate = view.findViewById(
+ com.android.internal.R.id.actions_container);
+ if (actionContainerCandidate instanceof FrameLayout) {
+ RemoteInputView existing = (RemoteInputView)
+ view.findViewWithTag(RemoteInputView.VIEW_TAG);
+
+ if (existing != null) {
+ existing.onNotificationUpdate();
+ }
+
+ if (existing == null && hasRemoteInput) {
+ ViewGroup actionContainer = (FrameLayout) actionContainerCandidate;
+ RemoteInputView riv = RemoteInputView.inflate(
+ mContext, actionContainer, entry, mRemoteInputController);
+
+ riv.setVisibility(View.INVISIBLE);
+ actionContainer.addView(riv, new LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT)
+ );
+ int color = entry.notification.getNotification().color;
+ if (color == Notification.COLOR_DEFAULT) {
+ color = mContext.getColor(R.color.default_remote_input_background);
+ }
+ riv.setBackgroundColor(color);
+ }
+ }
+ }
+
public void setGroupManager(NotificationGroupManager groupManager) {
mGroupManager = groupManager;
}
+ public void setRemoteInputController(RemoteInputController r) {
+ mRemoteInputController = r;
+ }
+
public void setExpandClickListener(OnClickListener expandClickListener) {
mExpandClickListener = expandClickListener;
}
public void updateExpandButtons(boolean expandable) {
+ mExpandable = expandable;
+ // if the expanded child has the same height as the collapsed one we hide it.
+ if (mExpandedChild != null && mExpandedChild.getHeight() != 0 &&
+ ((mIsHeadsUp && mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) ||
+ (!mIsHeadsUp && mExpandedChild.getHeight() == mContractedChild.getHeight()))) {
+ expandable = false;
+ }
if (mExpandedChild != null) {
mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c458d21..3cc1ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -115,17 +115,14 @@
updatedNotificationBuilder.makeBigContentView();
final RemoteViews newHeadsUpContentView =
updatedNotificationBuilder.makeHeadsUpContentView();
- final Notification updatedPublicNotification = updatedNotification.publicVersion;
- final RemoteViews newPubContentView = (updatedPublicNotification != null)
- ? Notification.Builder.recoverBuilder(
- ctx, updatedPublicNotification).makeContentView()
- : null;
+ final RemoteViews newPublicNotification
+ = updatedNotificationBuilder.makePublicContentView();
applyInPlace = compareRemoteViews(cachedContentView, newContentView)
&& compareRemoteViews(cachedBigContentView, newBigContentView)
&& compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
- && compareRemoteViews(cachedPublicContentView, newPubContentView);
- cachedPublicContentView = newPubContentView;
+ && compareRemoteViews(cachedPublicContentView, newPublicNotification);
+ cachedPublicContentView = newPublicNotification;
cachedHeadsUpContentView = newHeadsUpContentView;
cachedBigContentView = newBigContentView;
cachedContentView = newContentView;
@@ -136,14 +133,8 @@
cachedContentView = builder.makeContentView();
cachedBigContentView = builder.makeBigContentView();
cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+ cachedPublicContentView = builder.makePublicContentView();
- final Notification publicNotification =
- notification.getNotification().publicVersion;
- if (publicNotification != null) {
- final Notification.Builder publicBuilder
- = Notification.Builder.recoverBuilder(ctx, publicNotification);
- cachedPublicContentView = publicBuilder.makeContentView();
- }
applyInPlace = false;
}
return applyInPlace;
@@ -301,6 +292,15 @@
return false;
}
+ public boolean shouldSuppressScreenOn(String key) {
+ if (mRankingMap != null) {
+ mRankingMap.getRanking(key, mTmpRanking);
+ return (mTmpRanking.getSuppressedVisualEffects()
+ & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+ }
+ return false;
+ }
+
public int getImportance(String key) {
if (mRankingMap != null) {
mRankingMap.getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index 0081496..20a6e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -16,12 +16,24 @@
package com.android.systemui.statusbar;
+import android.annotation.IdRes;
+import android.app.INotificationManager;
+import android.app.Notification;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
+import android.widget.SeekBar;
+import android.widget.TextView;
import com.android.systemui.R;
@@ -33,6 +45,11 @@
private Drawable mBackground;
private int mClipTopAmount;
private int mActualHeight;
+ private boolean mExposed;
+ private RadioButton mApplyToTopic;
+ private SeekBar mSeekBar;
+ private Notification.Topic mTopic;
+ private INotificationManager mINotificationManager;
public NotificationGuts(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -83,6 +100,102 @@
}
}
+ void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row,
+ final int importance) {
+ mINotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mTopic = sbn.getNotification().getTopic() == null
+ ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString(
+ com.android.internal.R.string.default_notification_topic_label))
+ : sbn.getNotification().getTopic();
+ boolean doesAppUseTopics = false;
+ try {
+ doesAppUseTopics =
+ mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid());
+ } catch (RemoteException e) {}
+ final boolean appUsesTopics = doesAppUseTopics;
+
+ mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic);
+ if (appUsesTopics) {
+ mApplyToTopic.setChecked(true);
+ }
+ final View applyToApp = row.findViewById(R.id.apply_to_app);
+ final TextView topicSummary = ((TextView) row.findViewById(R.id.summary));
+ final TextView topicTitle = ((TextView) row.findViewById(R.id.title));
+ mSeekBar = (SeekBar) row.findViewById(R.id.seekbar);
+ mSeekBar.setMax(4);
+ mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ updateTitleAndSummary(progress);
+ if (fromUser) {
+ if (appUsesTopics) {
+ mApplyToTopic.setVisibility(View.VISIBLE);
+ mApplyToTopic.setText(
+ mContext.getString(R.string.apply_to_topic, mTopic.getLabel()));
+ applyToApp.setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ // no-op
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ // no-op
+ }
+
+ private void updateTitleAndSummary(int progress) {
+ switch (progress) {
+ case NotificationListenerService.Ranking.IMPORTANCE_NONE:
+ topicSummary.setText(mContext.getString(
+ R.string.notification_importance_blocked));
+ topicTitle.setText(mContext.getString(R.string.blocked_importance));
+ break;
+ case NotificationListenerService.Ranking.IMPORTANCE_LOW:
+ topicSummary.setText(mContext.getString(
+ R.string.notification_importance_low));
+ topicTitle.setText(mContext.getString(R.string.low_importance));
+ break;
+ case NotificationListenerService.Ranking.IMPORTANCE_DEFAULT:
+ topicSummary.setText(mContext.getString(
+ R.string.notification_importance_default));
+ topicTitle.setText(mContext.getString(R.string.default_importance));
+ break;
+ case NotificationListenerService.Ranking.IMPORTANCE_HIGH:
+ topicSummary.setText(mContext.getString(
+ R.string.notification_importance_high));
+ topicTitle.setText(mContext.getString(R.string.high_importance));
+ break;
+ case NotificationListenerService.Ranking.IMPORTANCE_MAX:
+ topicSummary.setText(mContext.getString(
+ R.string.notification_importance_max));
+ topicTitle.setText(mContext.getString(R.string.max_importance));
+ break;
+ }
+ }
+ });
+ mSeekBar.setProgress(importance);
+ }
+
+ void saveImportance(final StatusBarNotification sbn) {
+ int progress = mSeekBar.getProgress();
+ try {
+ if (mApplyToTopic.isChecked()) {
+ mINotificationManager.setTopicImportance(sbn.getPackageName(), sbn.getUid(), mTopic,
+ progress);
+ } else {
+ mINotificationManager.setAppImportance(
+ sbn.getPackageName(), sbn.getUid(), progress);
+ }
+ } catch (RemoteException e) {
+ // :(
+ }
+ }
+
public void setActualHeight(int actualHeight) {
mActualHeight = actualHeight;
invalidate();
@@ -103,4 +216,12 @@
// Prevents this view from creating a layer when alpha is animating.
return false;
}
+
+ public void setExposed(boolean exposed) {
+ mExposed = exposed;
+ }
+
+ public boolean areGutsExposed() {
+ return mExposed;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
index f243b00..d7e47c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java
@@ -30,11 +30,11 @@
public class RemoteInputController {
private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>();
- private final StatusBarWindowManager mStatusBarWindowManager;
+ private final ArrayList<Callback> mCallbacks = new ArrayList<>(3);
private final HeadsUpManager mHeadsUpManager;
public RemoteInputController(StatusBarWindowManager sbwm, HeadsUpManager headsUpManager) {
- mStatusBarWindowManager = sbwm;
+ addCallback(sbwm);
mHeadsUpManager = headsUpManager;
}
@@ -59,8 +59,12 @@
}
private void apply(NotificationData.Entry entry) {
- mStatusBarWindowManager.setRemoteInputActive(isRemoteInputActive());
mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry));
+ boolean remoteInputActive = isRemoteInputActive();
+ int N = mCallbacks.size();
+ for (int i = 0; i < N; i++) {
+ mCallbacks.get(i).onRemoteInputActive(remoteInputActive);
+ }
}
/**
@@ -99,4 +103,12 @@
}
+ public void addCallback(Callback callback) {
+ Preconditions.checkNotNull(callback);
+ mCallbacks.add(callback);
+ }
+
+ public interface Callback {
+ void onRemoteInputActive(boolean active);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
new file mode 100644
index 0000000..5c0f38c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.R.color;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ActivityStarter;
+import com.android.systemui.statusbar.phone.NavigationBarView;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
+import java.net.URISyntaxException;
+
+/**
+ * A custom navigation bar for the automotive use case.
+ * <p>
+ * The navigation bar in the automotive use case is more like a list of shortcuts, which we
+ * expect to be customizable by the car OEMs. This implementation populates the nav_buttons layout
+ * from resources rather than the layout file so customization would then mean updating
+ * arrays_car.xml appropriately in an overlay.
+ */
+class CarNavigationBarView extends NavigationBarView {
+ private ActivityStarter mActivityStarter;
+
+ public CarNavigationBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onFinishInflate() {
+ // Read up arrays_car.xml and populate the navigation bar here.
+ Context context = getContext();
+ Resources r = getContext().getResources();
+ TypedArray icons = r.obtainTypedArray(R.array.car_shortcut_icons);
+ TypedArray intents = r.obtainTypedArray(R.array.car_shortcut_intent_uris);
+ TypedArray longpressIntents =
+ r.obtainTypedArray(R.array.car_shortcut_longpress_intent_uris);
+
+ if (icons.length() != intents.length()) {
+ throw new RuntimeException("car_shortcut_icons and car_shortcut_intents do not match");
+ }
+
+ LinearLayout navButtons = (LinearLayout) findViewById(R.id.nav_buttons);
+ LinearLayout lightsOut = (LinearLayout) findViewById(R.id.lights_out);
+
+ for (int i = 0; i < icons.length(); i++) {
+ Drawable icon = icons.getDrawable(i);
+
+ try {
+ Intent intent = Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME);
+ Intent longpress = null;
+ String longpressUri = longpressIntents.getString(i);
+ if (!longpressUri.isEmpty()) {
+ longpress = Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME);
+ }
+
+ // nav_buttons and lights_out should match exactly.
+ navButtons.addView(makeButton(context, icon, intent, longpress));
+ lightsOut.addView(makeButton(context, icon, intent, longpress));
+ } catch (URISyntaxException e) {
+ throw new RuntimeException("Malformed intent uri", e);
+ }
+ }
+ }
+
+ private ImageButton makeButton(Context context, Drawable icon,
+ final Intent intent, final Intent longpress) {
+ ImageButton button = new ImageButton(context);
+
+ button.setImageDrawable(icon);
+ button.setScaleType(ScaleType.CENTER);
+ button.setBackgroundColor(color.transparent);
+ LinearLayout.LayoutParams lp =
+ new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
+ button.setLayoutParams(lp);
+
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mActivityStarter != null) {
+ mActivityStarter.startActivity(intent, true);
+ }
+ }
+ });
+
+ // Long click handlers are optional.
+ if (longpress != null) {
+ button.setLongClickable(true);
+ button.setOnLongClickListener(new OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (mActivityStarter != null) {
+ mActivityStarter.startActivity(longpress, true);
+ return true;
+ }
+ return false;
+ }
+ });
+ } else {
+ button.setLongClickable(false);
+ }
+
+ return button;
+ }
+
+ public void setActivityStarter(ActivityStarter activityStarter) {
+ mActivityStarter = activityStarter;
+ }
+
+ @Override
+ public void setDisabledFlags(int disabledFlags, boolean force) {
+ // TODO: Populate.
+ }
+
+ @Override
+ public void reorient() {
+ // We expect the car head unit to always have a fixed rotation so we ignore this. The super
+ // class implentation expects mRotatedViews to be populated, so if you call into it, there
+ // is a possibility of a NullPointerException.
+ }
+
+ @Override
+ public View getCurrentView() {
+ return this;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
new file mode 100644
index 0000000..a72b5d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.car;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+/**
+ * A status bar (and navigation bar) tailored for the automotive use case.
+ */
+public class CarStatusBar extends PhoneStatusBar {
+ @Override
+ protected void addNavigationBar() {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+ WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle("CarNavigationBar");
+ lp.windowAnimations = 0;
+ mWindowManager.addView(mNavigationBarView, lp);
+ }
+
+ @Override
+ protected void createNavigationBarView(Context context) {
+ if (mNavigationBarView != null) {
+ return;
+ }
+
+ CarNavigationBarView carNavBar =
+ (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
+ carNavBar.setActivityStarter(this);
+ mNavigationBarView = carNavBar;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 58c9722..d0c14f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -746,7 +746,7 @@
// Launch or bring the activity to front.
final IActivityManager iAm = ActivityManagerNative.getDefault();
try {
- iAm.startActivityFromRecents(taskPersistentId, INVALID_STACK_ID, null /* options */);
+ iAm.startActivityFromRecents(taskPersistentId, null /* options */);
} catch (RemoteException e) {
Slog.e(TAG, "Exception when activating a recent task", e);
} catch (IllegalArgumentException e) {
@@ -1104,6 +1104,10 @@
}
});
}
+
+ @Override
+ public void onActivityPinned() {
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 79bd626..cc85d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -29,6 +29,8 @@
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.stackdivider.DividerView;
import com.android.systemui.tuner.TunerService;
import static android.view.WindowManager.*;
@@ -189,7 +191,7 @@
mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS, createMode,
initialBounds);
if (mDragMode == DRAG_MODE_DIVIDER) {
- mDivider.getView().startDragging();
+ mDivider.getView().startDragging(false /* animate */);
}
mDockWindowTouchSlopExceeded = true;
MetricsLogger.action(mContext,
@@ -198,8 +200,10 @@
}
} else {
if (mDragMode == DRAG_MODE_DIVIDER) {
- mDivider.getView().resizeStack(
- !mIsVertical ? (int) event.getRawY() : (int) event.getRawX());
+ int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
+ SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
+ .calculateSnapTarget(position, 0f /* velocity */);
+ mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
} else if (mDragMode == DRAG_MODE_RECENTS) {
mRecentsComponent.onDraggingInRecents(event.getRawY());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index cddb1fc..02812a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,11 +36,13 @@
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
+import android.view.IDockedStackListener.Stub;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -155,8 +157,8 @@
final String how = "" + m.obj;
final int w = getWidth();
final int h = getHeight();
- final int vw = mCurrentView.getWidth();
- final int vh = mCurrentView.getHeight();
+ final int vw = getCurrentView().getWidth();
+ final int vh = getCurrentView().getHeight();
if (h != vh || w != vw) {
Log.w(TAG, String.format(
@@ -227,28 +229,28 @@
return mCurrentView;
}
- public View getRecentsButton() {
- return mCurrentView.findViewById(R.id.recent_apps);
+ public KeyButtonView getRecentsButton() {
+ return (KeyButtonView) getCurrentView().findViewById(R.id.recent_apps);
}
public View getMenuButton() {
- return mCurrentView.findViewById(R.id.menu);
+ return getCurrentView().findViewById(R.id.menu);
}
public View getBackButton() {
- return mCurrentView.findViewById(R.id.back);
+ return getCurrentView().findViewById(R.id.back);
}
public KeyButtonView getHomeButton() {
- return (KeyButtonView) mCurrentView.findViewById(R.id.home);
+ return (KeyButtonView) getCurrentView().findViewById(R.id.home);
}
public View getImeSwitchButton() {
- return mCurrentView.findViewById(R.id.ime_switcher);
+ return getCurrentView().findViewById(R.id.ime_switcher);
}
public View getAppShelf() {
- return mCurrentView.findViewById(R.id.app_shelf);
+ return getCurrentView().findViewById(R.id.app_shelf);
}
private void getIcons(Resources res) {
@@ -324,7 +326,7 @@
setSlippery(disableHome && disableRecent && disableBack && disableSearch);
}
- ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
+ ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
if (navButtons != null) {
LayoutTransition lt = navButtons.getLayoutTransition();
if (lt != null) {
@@ -377,7 +379,7 @@
private void updateLayoutTransitionsEnabled() {
boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled;
- ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons);
+ ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
LayoutTransition lt = navButtons.getLayoutTransition();
if (lt != null) {
if (enabled) {
@@ -455,6 +457,32 @@
getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
updateRTLOrder();
+
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
+ @Override
+ public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
+ }
+
+ @Override
+ public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ updateRecentsIcon(exists);
+ }
+ });
+ }
+ });
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed registering docked stack exists listener", e);
+ }
+ }
+
+ private void updateRecentsIcon(boolean dockedStackExists) {
+ getRecentsButton().setImageResource(dockedStackExists
+ ? R.drawable.ic_sysbar_docked
+ : R.drawable.ic_sysbar_recent);
}
public boolean isVertical() {
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 42fd872..ba20679 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1318,7 +1318,6 @@
mHeader.setExpansion(getHeaderExpansionFraction());
setQsTranslation(height);
requestScrollerTopPaddingUpdate(false /* animate */);
- updateNotificationScrim(height);
if (mKeyguardShowing) {
updateHeaderKeyguard();
}
@@ -1355,12 +1354,6 @@
}
}
- private void updateNotificationScrim(float height) {
- int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance;
- float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance);
- progress = Math.max(0.0f, Math.min(progress, 1.0f));
- }
-
private float getHeaderExpansionFraction() {
if (!mKeyguardShowing) {
return getQsExpansionFraction();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index e1a400d..6aa072f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -71,7 +71,6 @@
Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable());
return;
}
- ph.setBar(this);
mPanelHolder = ph;
final int N = ph.getChildCount();
for (int i=0; i<N; i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
index d7f34d5..5095ebb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java
@@ -28,7 +28,6 @@
public static final boolean DEBUG_GESTURES = true;
private int mSelectedPanelIndex = -1;
- private PanelBar mBar;
public PanelHolder(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -79,8 +78,4 @@
}
return false;
}
-
- public void setBar(PanelBar panelBar) {
- mBar = panelBar;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 5e54ba7..7b2498f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -58,7 +58,6 @@
private float mPeekHeight;
private float mHintDistance;
- private int mEdgeTapAreaWidth;
private float mInitialOffsetOnTouch;
private boolean mCollapsedAndHeadsUpOnDown;
private float mExpandedFraction = 0;
@@ -202,7 +201,6 @@
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mHintDistance = res.getDimension(R.dimen.hint_move_distance);
- mEdgeTapAreaWidth = res.getDimensionPixelSize(R.dimen.edge_tap_area_width);
mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 8f7c95e..d688250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -311,8 +311,6 @@
StatusBarIconController mIconController;
- private RemoteInputController mRemoteInputController;
-
// expanded notifications
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
View mExpandedContents;
@@ -730,32 +728,7 @@
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
- // Optionally show app shortcuts in the nav bar "shelf" area.
- if (shouldShowAppShelf()) {
- mNavigationBarView = (NavigationBarView) View.inflate(
- context, R.layout.navigation_bar_with_apps, null);
- } else {
- mNavigationBarView = (NavigationBarView) View.inflate(
- context, R.layout.navigation_bar, null);
- }
- mNavigationBarView.setDisabledFlags(mDisabled1);
- mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
- mNavigationBarView.setOnVerticalChangedListener(
- new NavigationBarView.OnVerticalChangedListener() {
- @Override
- public void onVerticalChanged(boolean isVertical) {
- if (mAssistManager != null) {
- mAssistManager.onConfigurationChanged();
- }
- mNotificationPanel.setQsScrimEnabled(!isVertical);
- }
- });
- mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- checkUserAutohide(v, event);
- return false;
- }});
+ createNavigationBarView(context);
}
} catch (RemoteException ex) {
// no window manager? good luck with that
@@ -981,6 +954,35 @@
return mStatusBarView;
}
+ protected void createNavigationBarView(Context context) {
+ // Optionally show app shortcuts in the nav bar "shelf" area.
+ if (shouldShowAppShelf()) {
+ mNavigationBarView = (NavigationBarView) View.inflate(
+ context, R.layout.navigation_bar_with_apps, null);
+ } else {
+ mNavigationBarView = (NavigationBarView) View.inflate(
+ context, R.layout.navigation_bar, null);
+ }
+ mNavigationBarView.setDisabledFlags(mDisabled1);
+ mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
+ mNavigationBarView.setOnVerticalChangedListener(
+ new NavigationBarView.OnVerticalChangedListener() {
+ @Override
+ public void onVerticalChanged(boolean isVertical) {
+ if (mAssistManager != null) {
+ mAssistManager.onConfigurationChanged();
+ }
+ mNotificationPanel.setQsScrimEnabled(!isVertical);
+ }
+ });
+ mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ checkUserAutohide(v, event);
+ return false;
+ }});
+ }
+
/** Returns true if the app shelf should be shown in the nav bar. */
private boolean shouldShowAppShelf() {
// Allow adb to override the default shelf behavior:
@@ -1088,6 +1090,7 @@
mKeyguardIndicationController.setStatusBarKeyguardViewManager(
mStatusBarKeyguardViewManager);
mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+ mRemoteInputController.addCallback(mStatusBarKeyguardViewManager);
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
}
@@ -1100,11 +1103,6 @@
return mStatusBarWindow;
}
- @Override
- protected RemoteInputView inflateRemoteInputView(ViewGroup root, Entry entry) {
- return RemoteInputView.inflate(mContext, root, entry, mRemoteInputController);
- }
-
public int getStatusBarHeight() {
if (mNaturalBarHeight < 0) {
final Resources res = mContext.getResources();
@@ -1198,7 +1196,7 @@
}
// For small-screen devices (read: phones) that lack hardware navigation buttons
- private void addNavigationBar() {
+ protected void addNavigationBar() {
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
if (mNavigationBarView == null) return;
@@ -1276,19 +1274,26 @@
}
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
- // Stop screensaver if the notification has a full-screen intent.
- // (like an incoming phone call)
- awakenDreams();
+ if (mNotificationData.shouldSuppressScreenOn(notification.getKey())) {
+ if (DEBUG) {
+ Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
+ }
+ } else {
+ // Stop screensaver if the notification has a full-screen intent.
+ // (like an incoming phone call)
+ awakenDreams();
- // not immersive & a full-screen alert should be shown
- if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
- try {
- EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
- notification.getKey());
- notification.getNotification().fullScreenIntent.send();
- shadeEntry.notifyFullScreenIntentLaunched();
- MetricsLogger.count(mContext, "note_fullscreen", 1);
- } catch (PendingIntent.CanceledException e) {
+ // not immersive & a full-screen alert should be shown
+ if (DEBUG)
+ Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+ try {
+ EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
+ notification.getKey());
+ notification.getNotification().fullScreenIntent.send();
+ shadeEntry.notifyFullScreenIntentLaunched();
+ MetricsLogger.count(mContext, "note_fullscreen", 1);
+ } catch (PendingIntent.CanceledException e) {
+ }
}
}
addNotificationViews(shadeEntry, ranking);
@@ -2987,6 +2992,7 @@
if (DEBUG) Log.v(TAG, "onReceive: " + intent);
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+ getKeyboardShortcuts().dismissKeyboardShortcutsDialog();
if (isCurrentProfile(getSendingUserId())) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
String reason = intent.getStringExtra("reason");
@@ -4127,32 +4133,6 @@
return false;
}
- // Recents
-
- @Override
- protected void showRecents(boolean triggeredFromAltTab) {
- // Set the recents visibility flag
- mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.showRecents(triggeredFromAltTab);
- }
-
- @Override
- protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- // Unset the recents visibility flag
- mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
- }
-
- @Override
- protected void toggleRecents() {
- // Toggle the recents visibility flag
- mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
- notifyUiVisibilityChanged(mSystemUiVisibility);
- super.toggleRecents();
- }
-
public void updateRecentsVisibility(boolean visible) {
// Update the recents visibility flag
if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c0887ca..ab37e6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -51,7 +51,6 @@
public PhoneStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
- Resources res = getContext().getResources();
mBarTransitions = new PhoneStatusBarTransitions(this);
}
@@ -102,7 +101,6 @@
@Override
public PanelView selectPanelForTouch(MotionEvent touch) {
- // No double swiping. If either panel is open, nothing else can be pulled down.
return mNotificationPanel.getExpandedHeight() > 0
? null
: mNotificationPanel;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 7f27ba7..5c856e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,30 +18,25 @@
import android.app.ActivityManager;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
-import android.os.Binder;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
-import android.os.RemoteException;
import android.provider.Settings;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.Log;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileServices;
import com.android.systemui.qs.tiles.AirplaneModeTile;
import com.android.systemui.qs.tiles.BatteryTile;
import com.android.systemui.qs.tiles.BluetoothTile;
import com.android.systemui.qs.tiles.CastTile;
import com.android.systemui.qs.tiles.CellularTile;
import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.CustomTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
@@ -64,6 +59,7 @@
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.tuner.ColorMatrixTile;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -75,7 +71,7 @@
import java.util.Map;
/** Platform implementation of the quick settings tile host **/
-public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tunable {
+public final class QSTileHost implements QSTile.Host, Tunable {
private static final String TAG = "QSTileHost";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -99,6 +95,7 @@
private final KeyguardMonitor mKeyguard;
private final SecurityController mSecurity;
private final BatteryController mBattery;
+ private final TileServices mServices;
private final List<Callback> mCallbacks = new ArrayList<>();
@@ -130,6 +127,8 @@
ht.start();
mLooper = ht.getLooper();
+ mServices = new TileServices(this, mLooper);
+
TunerService.get(mContext).addTunable(this, TILES_SETTING);
}
@@ -255,6 +254,10 @@
return mSecurity;
}
+ public TileServices getTileServices() {
+ return mServices;
+ }
+
@Override
public void onTuningChanged(String key, String newValue) {
if (!TILES_SETTING.equals(key)) {
@@ -305,50 +308,6 @@
TextUtils.join(",", specs), ActivityManager.getCurrentUser());
}
- @Override
- public void updateQsTile(Tile tile) throws RemoteException {
- verifyCaller(tile.getComponentName().getPackageName());
- CustomTile customTile = getTileForComponent(tile.getComponentName());
- if (customTile != null) {
- customTile.updateState(tile);
- customTile.refreshState();
- }
- }
-
- @Override
- public void onShowDialog(Tile tile) throws RemoteException {
- verifyCaller(tile.getComponentName().getPackageName());
- CustomTile customTile = getTileForComponent(tile.getComponentName());
- if (customTile != null) {
- customTile.onDialogShown();
- collapsePanels();
- }
- }
-
- private void verifyCaller(String packageName) {
- try {
- int uid = mContext.getPackageManager().getPackageUid(packageName,
- Binder.getCallingUserHandle().getIdentifier());
- if (Binder.getCallingUid() != uid) {
- throw new SecurityException("Component outside caller's uid");
- }
- } catch (NameNotFoundException e) {
- throw new SecurityException(e);
- }
- }
-
- private CustomTile getTileForComponent(ComponentName component) {
- // TODO: Build map for easier lookup.
- for (QSTile<?> qsTile : mTiles.values()) {
- if (qsTile instanceof CustomTile) {
- if (((CustomTile) qsTile).getComponent().equals(component)) {
- return (CustomTile) qsTile;
- }
- }
- }
- return null;
- }
-
public QSTile<?> createTile(String tileSpec) {
if (tileSpec.equals("wifi")) return WifiTile.isSupported(this)
? new WifiTile(this) : null;
@@ -368,10 +327,15 @@
else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
else if (tileSpec.equals("user")) return new UserTile(this);
else if (tileSpec.equals("battery")) return new BatteryTile(this);
+ else if (tileSpec.equals(ColorMatrixTile.COLOR_MATRIX_SPEC))
+ return new ColorMatrixTile(this);
// Intent tiles.
else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
- else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
+ else {
+ Log.w(TAG, "Bad tile spec: " + tileSpec);
+ return null;
+ }
}
public static List<String> loadTileSpecs(Context context, String tileList) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 1372cca..a91f6a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -24,7 +24,6 @@
import android.graphics.drawable.Animatable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
@@ -135,7 +134,6 @@
@Override
public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
mNextAlarm = nextAlarm;
- Log.d(TAG, "Got alarm update " + (nextAlarm != null));
if (nextAlarm != null) {
mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
}
@@ -179,10 +177,8 @@
private void updateListeners() {
if (mListening) {
- Log.d(TAG, "Listening for Alarms");
mNextAlarmController.addStateChangedCallback(this);
} else {
- Log.d(TAG, "Not listening for Alarms");
mNextAlarmController.removeStateChangedCallback(this);
}
}
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 05f6e57..f14f0d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,6 +31,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.RemoteInputController;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
@@ -40,7 +41,7 @@
* which is in turn, reported to this class by the current
* {@link com.android.keyguard.KeyguardViewBase}.
*/
-public class StatusBarKeyguardViewManager {
+public class StatusBarKeyguardViewManager implements RemoteInputController.Callback {
// When hiding the Keyguard with timing supplied from WindowManager, better be early than late.
private static final long HIDE_TIMING_CORRECTION_MS = -3 * 16;
@@ -69,12 +70,15 @@
private KeyguardBouncer mBouncer;
private boolean mShowing;
private boolean mOccluded;
+ private boolean mRemoteInputActive;
private boolean mFirstUpdate = true;
private boolean mLastShowing;
private boolean mLastOccluded;
private boolean mLastBouncerShowing;
private boolean mLastBouncerDismissible;
+ private boolean mLastRemoteInputActive;
+
private OnDismissAction mAfterKeyguardGoneAction;
private boolean mDeviceWillWakeUp;
private boolean mDeferScrimFadeOut;
@@ -199,6 +203,12 @@
mPhoneStatusBar.onScreenTurnedOn();
}
+ @Override
+ public void onRemoteInputActive(boolean active) {
+ mRemoteInputActive = active;
+ updateStates();
+ }
+
public void onScreenTurnedOff() {
mScreenTurnedOn = false;
}
@@ -429,18 +439,21 @@
boolean occluded = mOccluded;
boolean bouncerShowing = mBouncer.isShowing();
boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
+ boolean remoteInputActive = mRemoteInputActive;
- if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
+ if ((bouncerDismissible || !showing || remoteInputActive) !=
+ (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive)
|| mFirstUpdate) {
- if (bouncerDismissible || !showing) {
+ if (bouncerDismissible || !showing || remoteInputActive) {
mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK);
} else {
mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK);
}
}
- boolean navBarVisible = (!(showing && !occluded) || bouncerShowing);
- boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing);
+ boolean navBarVisible = (!(showing && !occluded) || bouncerShowing || remoteInputActive);
+ boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing
+ || mLastRemoteInputActive);
if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
if (mPhoneStatusBar.getNavigationBarView() != null) {
if (navBarVisible) {
@@ -477,6 +490,7 @@
mLastOccluded = occluded;
mLastBouncerShowing = bouncerShowing;
mLastBouncerDismissible = bouncerDismissible;
+ mLastRemoteInputActive = remoteInputActive;
mPhoneStatusBar.onKeyguardViewManagerStatesUpdated();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index abe51ac..9d2f0de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -30,6 +30,7 @@
import com.android.keyguard.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import java.io.FileDescriptor;
@@ -39,7 +40,7 @@
/**
* Encapsulates all logic for the status bar window state management.
*/
-public class StatusBarWindowManager {
+public class StatusBarWindowManager implements RemoteInputController.Callback {
private final Context mContext;
private final WindowManager mWindowManager;
@@ -292,7 +293,8 @@
apply(mCurrentState);
}
- public void setRemoteInputActive(boolean remoteInputActive) {
+ @Override
+ public void onRemoteInputActive(boolean remoteInputActive) {
mCurrentState.remoteInputActive = remoteInputActive;
apply(mCurrentState);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 5cfd174..b38c3fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -378,23 +378,22 @@
return;
}
if (mHasPinnedNotification) {
- int minX = Integer.MAX_VALUE;
+ int minX = 0;
int maxX = 0;
- int minY = Integer.MAX_VALUE;
int maxY = 0;
for (HeadsUpEntry entry : mSortedEntries) {
ExpandableNotificationRow row = entry.entry.row;
if (row.isPinned()) {
row.getLocationOnScreen(mTmpTwoArray);
- minX = Math.min(minX, mTmpTwoArray[0]);
- minY = Math.min(minY, 0);
- maxX = Math.max(maxX, mTmpTwoArray[0] + row.getWidth());
- maxY = Math.max(maxY, row.getHeadsUpHeight());
+ minX = mTmpTwoArray[0];
+ maxX = mTmpTwoArray[0] + row.getWidth();
+ maxY = row.getHeadsUpHeight();
+ break;
}
}
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(minX, minY, maxX, maxY + mNotificationsTopPadding);
+ info.touchableRegion.set(minX, 0, maxX, maxY + mNotificationsTopPadding);
} else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index beaa3ad..baccd2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -56,6 +56,7 @@
private ExpandableNotificationRow mNotificationParent;
private HybridNotificationView mGroupOverflowContainer;
private ViewState mGroupOverFlowState;
+ private int mRealHeight;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -111,8 +112,8 @@
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
+ int size = MeasureSpec.getSize(heightMeasureSpec);
if (hasFixedHeight || isHeightLimited) {
- int size = MeasureSpec.getSize(heightMeasureSpec);
ownMaxHeight = Math.min(ownMaxHeight, size);
}
int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
@@ -133,9 +134,19 @@
if (mGroupOverflowContainer != null) {
mGroupOverflowContainer.measure(widthMeasureSpec, newHeightSpec);
}
+ mRealHeight = height;
+ if (heightMode != MeasureSpec.UNSPECIFIED) {
+ height = Math.min(height, size);
+ }
setMeasuredDimension(width, height);
}
+ @Override
+ public boolean pointInView(float localX, float localY, float slop) {
+ return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) &&
+ localY < (mRealHeight + slop);
+ }
+
/**
* Add a child notification to this view.
*
@@ -452,6 +463,10 @@
}
public int getMinHeight() {
+ return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
+ }
+
+ public int getMinExpandHeight() {
return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 2ce19a2..0ed1527 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -118,7 +118,7 @@
/**
* The algorithm which calculates the properties for our children
*/
- private StackScrollAlgorithm mStackScrollAlgorithm;
+ private final StackScrollAlgorithm mStackScrollAlgorithm;
/**
* The current State this Layout is in
@@ -258,6 +258,7 @@
mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, getContext());
mSwipeHelper.setLongPressListener(mLongPressListener);
+ mStackScrollAlgorithm = new StackScrollAlgorithm(context);
initView(context);
if (DEBUG) {
setWillNotDraw(false);
@@ -303,8 +304,7 @@
.getDimensionPixelSize(R.dimen.notification_min_height);
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
- mStackScrollAlgorithm = new StackScrollAlgorithm(context);
- mStackScrollAlgorithm.setDimmed(mAmbientState.isDimmed());
+ mStackScrollAlgorithm.initView(context);
mPaddingBetweenElementsDimmed = context.getResources()
.getDimensionPixelSize(R.dimen.notification_padding_dimmed);
mPaddingBetweenElementsNormal = context.getResources()
@@ -1338,7 +1338,7 @@
/**
* @return the first child which has visibility unequal to GONE
*/
- private ExpandableView getFirstChildNotGone() {
+ public ExpandableView getFirstChildNotGone() {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
@@ -2836,7 +2836,6 @@
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
mAmbientState.setHeadsUpManager(headsUpManager);
- mStackScrollAlgorithm.setHeadsUpManager(headsUpManager);
}
public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 59b446b..5496963 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -25,7 +25,6 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
import java.util.List;
@@ -68,19 +67,22 @@
private int mBottomStackSlowDownLength;
private int mTopStackSlowDownLength;
private int mCollapseSecondCardPadding;
- private boolean mIsSmallScreen;
- private int mMaxNotificationHeight;
private boolean mScaleDimmed;
- private HeadsUpManager mHeadsUpManager;
+ private ExpandableView mFirstChild;
private int mFirstChildMinHeight;
+ private boolean mDimmed;
public StackScrollAlgorithm(Context context) {
- initConstants(context);
- updatePadding(false);
+ initView(context);
}
- private void updatePadding(boolean dimmed) {
- mPaddingBetweenElements = dimmed && mScaleDimmed
+ public void initView(Context context) {
+ initConstants(context);
+ updatePadding();
+ }
+
+ private void updatePadding() {
+ mPaddingBetweenElements = mDimmed && mScaleDimmed
? mPaddingBetweenElementsDimmed
: mPaddingBetweenElementsNormal;
mTopStackTotalSize = mTopStackSlowDownLength + mPaddingBetweenElements
@@ -110,8 +112,6 @@
.getDimensionPixelSize(R.dimen.notifications_top_padding);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
- mMaxNotificationHeight = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_max_height);
mTopStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.top_stack_peek_amount);
mBottomStackPeekSize = context.getResources()
@@ -149,6 +149,7 @@
algorithmState.scrolledPixelsTop = 0;
algorithmState.itemsInBottomStack = 0.0f;
algorithmState.partialInBottom = 0.0f;
+ mFirstChildMinHeight = mFirstChild == null ? 0 : mFirstChild.getMinHeight();
float bottomOverScroll = ambientState.getOverScrollAmount(false /* onTop */);
int scrollY = ambientState.getScrollY();
@@ -544,7 +545,7 @@
if (row.isPinned()) {
childState.yTranslation = Math.max(childState.yTranslation,
mNotificationsTopPadding);
- childState.height = row.getHeadsUpHeight();
+ childState.height = Math.max(row.getHeadsUpHeight(), childState.height);
if (!isTopEntry) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
// the top most z-position
@@ -933,10 +934,7 @@
}
public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
- int firstItemMinHeight = hostView.getFirstItemMinHeight();
- if (firstItemMinHeight != mFirstChildMinHeight) {
- mFirstChildMinHeight = firstItemMinHeight;
- }
+ mFirstChild = hostView.getFirstChildNotGone();
if (mIsExpansionChanging) {
hostView.post(new Runnable() {
@Override
@@ -948,7 +946,8 @@
}
public void setDimmed(boolean dimmed) {
- updatePadding(dimmed);
+ mDimmed = dimmed;
+ updatePadding();
}
public void onReset(ExpandableView view) {
@@ -957,10 +956,6 @@
}
}
- public void setHeadsUpManager(HeadsUpManager headsUpManager) {
- mHeadsUpManager = headsUpManager;
- }
-
class StackScrollAlgorithmState {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
new file mode 100644
index 0000000..8ed1b06
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixFragment.java
@@ -0,0 +1,355 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tuner;
+
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.DropDownPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceViewHolder;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.Objects;
+
+public class ColorMatrixFragment extends PreferenceFragment implements TunerService.Tunable {
+
+ private static final String TAG = "ColorMatrixFragment";
+
+ public static final int CUSTOM_INDEX = 2;
+
+ // Night mode ~= 3400 K
+ private static final float[] NIGHT_VALUES = new float[] {
+ 1, 0, 0, 0,
+ 0, .754f, 0, 0,
+ 0, 0, .516f, 0,
+ 0, 0, 0, 1,
+ };
+ public static final float[] IDENTITY_MATRIX = new float[]{
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1,
+ };
+ private static final long RESET_DELAY = 10000;
+
+ private boolean mCustomEnabled;
+ private DropDownPreference mSelectPreference;
+ private String mCurrentValue;
+ private String mCustomValues;
+ private SwitchPreference mEnableCustomPreference;
+ private MatrixPreference mCustomPreference;
+ private SwitchPreference mShowQs;
+ private String mTiles;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Context context = getContext();
+ TunerService.get(context).addTunable(this, ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED,
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, QSTileHost.TILES_SETTING,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ final Context context = getPreferenceManager().getContext();
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(context));
+
+ mSelectPreference = new DropDownPreference(context);
+ mSelectPreference.setTitle(R.string.color_transform);
+ mSelectPreference.setSummary("%s");
+ mSelectPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ int index = Integer.parseInt((String) newValue);
+ Settings.Secure.putString(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, getValues()[index]);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mSelectPreference);
+
+ mShowQs = new SwitchPreference(context);
+ mShowQs.setTitle(R.string.color_matrix_show_qs);
+ mShowQs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean showTile = (Boolean) newValue;
+ String newTiles;
+ if (showTile) {
+ newTiles = mTiles != null ? mTiles + "," + ColorMatrixTile.COLOR_MATRIX_SPEC
+ : "default," + ColorMatrixTile.COLOR_MATRIX_SPEC;
+ } else {
+ newTiles =
+ mTiles.replace(mTiles.contains(ColorMatrixTile.COLOR_MATRIX_SPEC+ ",")
+ ? ColorMatrixTile.COLOR_MATRIX_SPEC + ","
+ : "," + ColorMatrixTile.COLOR_MATRIX_SPEC, "");
+ }
+ Settings.Secure.putString(context.getContentResolver(), QSTileHost.TILES_SETTING,
+ newTiles);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mShowQs);
+
+ mEnableCustomPreference = new SwitchPreference(context);
+ mEnableCustomPreference.setTitle(R.string.color_enable_custom);
+ mEnableCustomPreference.setOnPreferenceChangeListener(
+ new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ boolean enabled = (Boolean) newValue;
+ Settings.Secure.putInt(context.getContentResolver(),
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED, enabled ? 1 : 0);
+ return true;
+ }
+ });
+ getPreferenceScreen().addPreference(mEnableCustomPreference);
+
+ mCustomPreference = new MatrixPreference(context);
+ getPreferenceScreen().addPreference(mCustomPreference);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ TunerService.get(getContext()).removeTunable(this);
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+ mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
+ mEnableCustomPreference.setChecked(mCustomEnabled);
+ mCustomPreference.setEnabled(mCustomEnabled);
+ updateSelectOptions();
+ } else if (ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mCustomValues = newValue;
+ mCustomPreference.setValues(mCustomValues);
+ updateSelectOptions();
+ } else if (QSTileHost.TILES_SETTING.equals(key)) {
+ mTiles = newValue;
+ boolean hasTile = newValue != null
+ && newValue.contains(ColorMatrixTile.COLOR_MATRIX_SPEC);
+ mShowQs.setChecked(hasTile);
+ } else {
+ mCurrentValue = newValue;
+ updateSelectOptions();
+ }
+ }
+
+ private void updateSelectOptions() {
+ final int N = CUSTOM_INDEX + (mCustomEnabled ? 1 : 0);
+ String[] values = new String[N];
+ CharSequence[] totalNames = getColorTitles(getContext());
+ CharSequence[] names = new CharSequence[N];
+ for (int i = 0; i < N; i++) {
+ values[i] = String.valueOf(i);
+ names[i] = totalNames[i];
+ }
+ mSelectPreference.setEntries(names);
+ mSelectPreference.setEntryValues(values);
+ String[] entries = getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (Objects.equals(entries[i], mCurrentValue)) {
+ mSelectPreference.setValueIndex(i);
+ return;
+ }
+ }
+ mSelectPreference.setSummary(R.string.color_matrix_unknown);
+ return;
+ }
+
+ private String[] getValues() {
+ String[] ret = getColorTransforms();
+ // Fill in custom based on tuner settings.
+ ret[CUSTOM_INDEX] = mCustomValues;
+ return ret;
+ }
+
+ private void startRevertTimer() {
+ getView().postDelayed(mResetColorMatrix, RESET_DELAY);
+ }
+
+ private void onApply() {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ ColorMatrixTile.COLOR_MATRIX_CUSTOM_VALUES, mCurrentValue);
+ getView().removeCallbacks(mResetColorMatrix);
+ }
+
+ private void onRevert() {
+ getView().removeCallbacks(mResetColorMatrix);
+ mResetColorMatrix.run();
+ }
+
+ public static String[] getColorTransforms() {
+ return new String[] {
+ null,
+ toString(NIGHT_VALUES),
+ null, // Blank spot for custom values
+ null, // Unknown
+ };
+ }
+
+ public static CharSequence[] getColorTitles(Context context) {
+ return new CharSequence[] {
+ context.getString(R.string.color_matrix_none),
+ context.getString(R.string.color_matrix_night),
+ context.getString(R.string.color_matrix_custom),
+ context.getString(R.string.color_matrix_unknown),
+ };
+ }
+
+ private static String toString(float[] values) {
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < values.length; i++) {
+ if (builder.length() != 0) {
+ builder.append(',');
+ }
+ builder.append(values[i]);
+ }
+ return builder.toString();
+ }
+
+ private final Runnable mResetColorMatrix = new Runnable() {
+ @Override
+ public void run() {
+ ((DialogFragment) getFragmentManager().findFragmentByTag("RevertWarning")).dismiss();
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, null);
+ }
+ };
+
+ private class MatrixPreference extends Preference implements View.OnClickListener {
+ private float[] mValues;
+
+ public MatrixPreference(Context context) {
+ super(context);
+ setLayoutResource(R.layout.preference_matrix);
+ }
+
+ public void setValues(String customValues) {
+ if (customValues == null) {
+ mValues = IDENTITY_MATRIX;
+ } else {
+ String[] strValues = customValues.split(",");
+ mValues = new float[strValues.length];
+ for (int i = 0; i < mValues.length; i++) {
+ mValues[i] = Float.parseFloat(strValues[i]);
+ }
+ }
+ notifyChanged();
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ ViewGroup vg = (ViewGroup) holder.itemView.findViewById(R.id.edit_group);
+ if (mValues == null) {
+ return;
+ }
+ int childIndex = 0;
+ for (int i = 0; i < mValues.length; i++) {
+ final int index = i;
+ while (!(vg.getChildAt(childIndex) instanceof EditText)) {
+ childIndex++;
+ }
+ final EditText editText = (EditText) vg.getChildAt(childIndex++);
+ editText.setText(String.valueOf(mValues[i]));
+ editText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (TextUtils.isEmpty(s.toString())) {
+ return;
+ }
+ try {
+ mValues[index] = Float.parseFloat(s.toString());
+ } catch (NumberFormatException e) {
+ mValues[index] = 0;
+ }
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+ });
+ }
+ ((Button) holder.itemView.findViewById(R.id.apply)).setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ Settings.Secure.putString(getContext().getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX,
+ ColorMatrixFragment.toString(mValues));
+ RevertWarning.show(ColorMatrixFragment.this);
+ }
+
+ }
+
+ public static class RevertWarning extends DialogFragment
+ implements DialogInterface.OnClickListener {
+
+ public static void show(ColorMatrixFragment fragment) {
+ RevertWarning warning = new RevertWarning();
+ warning.setTargetFragment(fragment, 0);
+ warning.show(fragment.getFragmentManager(), "RevertWarning");
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog alertDialog = new AlertDialog.Builder(getContext())
+ .setTitle(R.string.color_revert_title)
+ .setMessage(R.string.color_revert_message)
+ .setPositiveButton(R.string.ok, this)
+ .create();
+ alertDialog.setCanceledOnTouchOutside(true);
+ return alertDialog;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ ((ColorMatrixFragment) getTargetFragment()).onRevert();
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ((ColorMatrixFragment) getTargetFragment()).onApply();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
new file mode 100644
index 0000000..1fd2352
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ColorMatrixTile.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.tuner;
+
+import android.app.ActivityManager;
+import android.provider.Settings;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import libcore.util.Objects;
+
+public class ColorMatrixTile extends QSTile<QSTile.State> implements TunerService.Tunable {
+
+ public static final String COLOR_MATRIX_CUSTOM_ENABLED = "tuner_color_custom_enabled";
+ public static final String COLOR_MATRIX_CUSTOM_VALUES = "tuner_color_custom_values";
+
+ public static final String COLOR_MATRIX_SPEC = "colors";
+
+ private int mIndex;
+ private String mCurrentValue;
+
+ private boolean mCustomEnabled;
+ private String[] mValues;
+ private CharSequence[] mValueTitles;
+
+ public ColorMatrixTile(Host host) {
+ super(host);
+ }
+
+ @Override
+ public void setListening(boolean listening) {
+ if (listening) {
+ mValues = ColorMatrixFragment.getColorTransforms();
+ mValueTitles = ColorMatrixFragment.getColorTitles(mContext);
+ TunerService.get(mContext).addTunable(this, COLOR_MATRIX_CUSTOM_ENABLED,
+ COLOR_MATRIX_CUSTOM_VALUES,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX);
+ } else {
+ TunerService.get(mContext).removeTunable(this);
+ }
+ }
+
+ @Override
+ protected State newTileState() {
+ return new State();
+ }
+
+ @Override
+ protected void handleClick() {
+ mIndex++;
+ if (!mCustomEnabled && (mIndex == ColorMatrixFragment.CUSTOM_INDEX)) {
+ mIndex++;
+ }
+ if (mIndex == mValues.length - 1) {
+ mIndex = 0;
+ }
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX, mValues[mIndex],
+ ActivityManager.getCurrentUser());
+ refreshState();
+ }
+
+ @Override
+ public void onTuningChanged(String key, String newValue) {
+ if (COLOR_MATRIX_CUSTOM_ENABLED.equals(key)) {
+ mCustomEnabled = newValue != null && Integer.parseInt(newValue) != 0;
+ } else if (COLOR_MATRIX_CUSTOM_VALUES.equals(key)) {
+ mValues[ColorMatrixFragment.CUSTOM_INDEX] = newValue;
+ } else {
+ mCurrentValue = newValue;
+ }
+ // Last value is unknown, default to that.
+ mIndex = mValues.length - 1;
+ for (int i = 0; i < mValues.length - 1; i++) {
+ if (Objects.equal(mCurrentValue, mValues[i])) {
+ mIndex = i;
+ break;
+ }
+ }
+ refreshState();
+ }
+
+ @Override
+ protected void handleUpdateState(State state, Object arg) {
+ state.icon = ResourceIcon.get(R.drawable.ic_colorize);
+ state.label = mValueTitles[mIndex];
+ state.contentDescription = mValueTitles[mIndex];
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsLogger.QS_COLOR_MATRIX;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index a2b062c..f1de234 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -22,12 +22,12 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.preference.SwitchPreference;
import android.provider.Settings;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.PreferenceScreen;
import android.view.MenuItem;
import com.android.internal.logging.MetricsLogger;
@@ -56,9 +56,7 @@
private SwitchPreference mOnSwitch;
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
Context context = getContext();
mEnabledSwitch = new SwitchPreference(context);
mEnabledSwitch.setTitle(R.string.enable_demo_mode);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index dcb0d8d..920ec75 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -18,8 +18,8 @@
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.preference.SwitchPreference;
import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -38,15 +38,15 @@
}
@Override
- protected void onAttachedToActivity() {
- super.onAttachedToActivity();
+ public void onAttached() {
+ super.onAttached();
TunerService.get(getContext()).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
}
@Override
- protected void onDetachedFromActivity() {
+ public void onDetached() {
TunerService.get(getContext()).removeTunable(this);
- super.onDetachedFromActivity();
+ super.onDetached();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index c84f618..4173ecc 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -15,16 +15,64 @@
*/
package com.android.systemui.tuner;
-import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
import android.os.Bundle;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.util.Log;
-public class TunerActivity extends Activity {
+import com.android.settingslib.drawer.SettingsDrawerActivity;
+import com.android.systemui.R;
+
+public class TunerActivity extends SettingsDrawerActivity implements
+ PreferenceFragment.OnPreferenceStartFragmentCallback,
+ PreferenceFragment.OnPreferenceStartScreenCallback {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getFragmentManager().beginTransaction().replace(android.R.id.content, new TunerFragment())
+ getFragmentManager().beginTransaction().replace(R.id.content_frame, new TunerFragment())
.commit();
}
+ @Override
+ public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
+ try {
+ Class<?> cls = Class.forName(pref.getFragment());
+ Fragment fragment = (Fragment) cls.newInstance();
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ transaction.replace(R.id.content_frame, fragment);
+ transaction.addToBackStack("PreferenceFragment");
+ transaction.commit();
+ return true;
+ } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ Log.d("TunerActivity", "Problem launching fragment", e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onPreferenceStartScreen(PreferenceFragment caller, PreferenceScreen pref) {
+ FragmentTransaction transaction = getFragmentManager().beginTransaction();
+ SubSettingsFragment fragment = new SubSettingsFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(PreferenceFragment.ARG_PREFERENCE_ROOT, pref.getKey());
+ fragment.setArguments(b);
+ fragment.setTargetFragment(caller, 0);
+ transaction.replace(R.id.content_frame, fragment);
+ transaction.addToBackStack("PreferenceFragment");
+ transaction.commit();
+ return true;
+ }
+
+ public static class SubSettingsFragment extends PreferenceFragment {
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ setPreferenceScreen((PreferenceScreen) ((PreferenceFragment) getTargetFragment())
+ .getPreferenceScreen().findPreference(rootKey));
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index b620b50b..a3fe6bb 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -24,20 +24,19 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceFragment;
-import android.preference.SwitchPreference;
import android.provider.Settings;
import android.provider.Settings.System;
+import android.support.v14.preference.PreferenceFragment;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.Preference.OnPreferenceChangeListener;
+import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
-import com.android.systemui.qs.QSPanel;
-import com.android.systemui.tuner.TunerService.Tunable;
import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
@@ -45,8 +44,6 @@
private static final String TAG = "TunerFragment";
- private static final String KEY_QS_TUNER = "qs_tuner";
- private static final String KEY_DEMO_MODE = "demo_mode";
private static final String KEY_BATTERY_PCT = "battery_pct";
public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
@@ -59,23 +56,18 @@
private SwitchPreference mBatteryPct;
+ @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.tuner_prefs);
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
setHasOptionsMenu(true);
+ }
- findPreference(KEY_DEMO_MODE).setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- FragmentTransaction ft = getFragmentManager().beginTransaction();
- ft.replace(android.R.id.content, new DemoModeFragment(), "DemoMode");
- ft.addToBackStack(null);
- ft.commit();
- return true;
- }
- });
+ @Override
+ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
+ addPreferencesFromResource(R.xml.tuner_prefs);
+
mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT);
if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
0) == 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 1e3b0f1..47a4667 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -32,7 +32,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;
-
+import android.util.ArraySet;
import com.android.systemui.BatteryMeterDrawable;
import com.android.systemui.DemoMode;
import com.android.systemui.R;
@@ -41,9 +41,8 @@
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
+import java.util.Set;
public class TunerService extends SystemUI {
@@ -54,7 +53,7 @@
// Map of Uris we listen on to their settings keys.
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
- private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>();
+ private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
private ContentResolver mContentResolver;
private int mCurrentUser;
@@ -85,7 +84,7 @@
private void addTunable(Tunable tunable, String key) {
if (!mTunableLookup.containsKey(key)) {
- mTunableLookup.put(key, new ArrayList<Tunable>());
+ mTunableLookup.put(key, new ArraySet<Tunable>());
}
mTunableLookup.get(key).add(tunable);
Uri uri = Settings.Secure.getUriFor(key);
@@ -99,7 +98,7 @@
}
public void removeTunable(Tunable tunable) {
- for (List<Tunable> list : mTunableLookup.values()) {
+ for (Set<Tunable> list : mTunableLookup.values()) {
list.remove(tunable);
}
}
@@ -116,7 +115,7 @@
public void reloadSetting(Uri uri) {
String key = mListeningUris.get(uri);
- List<Tunable> tunables = mTunableLookup.get(key);
+ Set<Tunable> tunables = mTunableLookup.get(key);
if (tunables == null) {
return;
}
@@ -153,8 +152,11 @@
private static TunerService sInstance;
public static TunerService get(Context context) {
- SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
- TunerService service = sysUi.getComponent(TunerService.class);
+ TunerService service = null;
+ if (context.getApplicationContext() instanceof SystemUIApplication) {
+ SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
+ service = sysUi.getComponent(TunerService.class);
+ }
if (service == null) {
// Can't get it as a component, must in the tuner, lets just create one for now.
return getStaticService(context);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 54078b0..7ad752e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -2,8 +2,8 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.preference.SwitchPreference;
import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
import com.android.systemui.R;
@@ -21,15 +21,15 @@
}
@Override
- protected void onAttachedToActivity() {
- super.onAttachedToActivity();
+ public void onAttached() {
+ super.onAttached();
TunerService.get(getContext()).addTunable(this, getKey());
}
@Override
- protected void onDetachedFromActivity() {
+ public void onDetached() {
TunerService.get(getContext()).removeTunable(this);
- super.onDetachedFromActivity();
+ super.onDetached();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 9d4ec10..3c63aae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -648,7 +648,7 @@
if (D.BUG) Log.d(TAG, "updateFooterH");
final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
- && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
+ && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded);
if (wasVisible != visible && !visible) {
prepareForCollapse();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cd47ac1..38d8de0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -510,7 +510,7 @@
GregorianCalendar weekRange = new GregorianCalendar();
final long now = weekRange.getTimeInMillis();
setToMidnight(weekRange);
- weekRange.roll(Calendar.DATE, 6);
+ weekRange.add(Calendar.DATE, 6);
final long nextAlarmMs = mController.getNextAlarm();
if (nextAlarmMs > 0) {
GregorianCalendar nextAlarm = new GregorianCalendar();
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 9cf64d3..b7a41e2 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -21,7 +21,8 @@
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
-LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.systemui:com.android.keyguard
+LOCAL_AAPT_FLAGS := --auto-add-overlay \
+ --extra-packages com.android.systemui:com.android.keyguard:android.support.v14.preference:android.support.v7.preference:android.support.v7.appcompat:android.support.v7.recyclerview
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
$(call all-Iaidl-files-under, src) \
@@ -30,6 +31,10 @@
src/com/android/systemui/EventLogTags.logtags
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
+ frameworks/support/v7/preference/res \
+ frameworks/support/v14/preference/res \
+ frameworks/support/v7/appcompat/res \
+ frameworks/support/v7/recyclerview/res \
frameworks/base/packages/SystemUI/res \
frameworks/base/packages/Keyguard/res
@@ -40,7 +45,10 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target \
Keyguard \
- android-support-v7-recyclerview
+ android-support-v7-recyclerview \
+ android-support-v7-preference \
+ android-support-v7-appcompat \
+ android-support-v14-preference
# sign this with platform cert, so this test is allowed to inject key events into
# UI it doesn't own. This is necessary to allow screenshots to be taken
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c21af24..2825601 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -19,10 +19,16 @@
<uses-permission android:name="android.permission.INJECT_EVENTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
+
+ <service
+ android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
+ android:process=":killable" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
new file mode 100644
index 0000000..6ebf488
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.external;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+public class TileLifecycleManagerTests extends AndroidTestCase {
+ public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
+ public static final String EXTRA_CALLBACK = "callback";
+
+ private HandlerThread mThread;
+ private Handler mHandler;
+ private TileLifecycleManager mStateManager;
+ private final Object mBroadcastLock = new Object();
+ private final ArraySet<String> mCallbacks = new ArraySet<>();
+ private boolean mBound;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mThread = new HandlerThread("TestThread");
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper());
+ mStateManager = new TileLifecycleManager(mHandler, getContext(),
+ new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+ mCallbacks.clear();
+ getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (mBound) {
+ unbindService();
+ }
+ mThread.quit();
+ getContext().unregisterReceiver(mReceiver);
+ }
+
+ public void testSync() {
+ syncWithHandler();
+ }
+
+ public void testBind() {
+ bindService();
+ waitForCallback("onCreate");
+ }
+
+ public void testUnbind() {
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ }
+
+ public void testTileServiceCallbacks() {
+ bindService();
+ waitForCallback("onCreate");
+
+ mStateManager.onTileAdded();
+ waitForCallback("onTileAdded");
+ mStateManager.onStartListening();
+ waitForCallback("onStartListening");
+ mStateManager.onClick(null);
+ waitForCallback("onClick");
+ mStateManager.onStopListening();
+ waitForCallback("onStopListening");
+ mStateManager.onTileRemoved();
+ waitForCallback("onTileRemoved");
+
+ unbindService();
+ }
+
+ public void testAddedBeforeBind() {
+ mStateManager.onTileAdded();
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ }
+
+ public void testListeningBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ waitForCallback("onStartListening");
+ }
+
+ public void testClickBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onClick(null);
+
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onTileAdded");
+ waitForCallback("onStartListening");
+ waitForCallback("onClick");
+ }
+
+ public void testListeningNotListeningBeforeBind() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onStopListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ assertFalse(mCallbacks.contains("onStartListening"));
+ }
+
+ public void testNoClickOfNotListeningAnymore() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+ mStateManager.onClick(null);
+ mStateManager.onStopListening();
+
+ bindService();
+ waitForCallback("onCreate");
+ unbindService();
+ waitForCallback("onDestroy");
+ assertFalse(mCallbacks.contains("onClick"));
+ }
+
+ public void testComponentEnabling() {
+ mStateManager.onTileAdded();
+ mStateManager.onStartListening();
+
+ PackageManager pm = getContext().getPackageManager();
+ pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+ bindService();
+ assertTrue(mStateManager.mReceiverRegistered);
+
+ pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+ PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+ waitForCallback("onCreate");
+ }
+
+ public void testKillProcess() {
+ mStateManager.onStartListening();
+ bindService();
+ waitForCallback("onCreate");
+ waitForCallback("onStartListening");
+
+ getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
+
+ waitForCallback("onCreate");
+ waitForCallback("onStartListening");
+ }
+
+ private void bindService() {
+ mBound = true;
+ mStateManager.setBindService(true);
+ }
+
+ private void unbindService() {
+ mBound = false;
+ mStateManager.setBindService(false);
+ }
+
+ private void waitForCallback(String callback) {
+ for (int i = 0; i < 25; i++) {
+ if (mCallbacks.contains(callback)) {
+ mCallbacks.remove(callback);
+ return;
+ }
+ synchronized (mBroadcastLock) {
+ try {
+ mBroadcastLock.wait(500);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (mCallbacks.contains(callback)) {
+ mCallbacks.remove(callback);
+ return;
+ }
+ fail("Didn't receive callback: " + callback);
+ }
+
+ private void syncWithHandler() {
+ final Object lock = new Object();
+ synchronized (lock) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (lock) {
+ lock.notify();
+ }
+ }
+ });
+ try {
+ lock.wait(5000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
+ synchronized (mBroadcastLock) {
+ mBroadcastLock.notify();
+ }
+ }
+ };
+
+ public static class FakeTileService extends Service {
+ public static final String ACTION_KILL = "com.android.systemui.test.KILL";
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new IQSTileService.Stub() {
+
+ @Override
+ public void setQSService(IQSService service) {
+
+ }
+
+ @Override
+ public void setQSTile(Tile tile) throws RemoteException {
+ }
+
+ @Override
+ public void onTileAdded() throws RemoteException {
+ sendCallback("onTileAdded");
+ }
+
+ @Override
+ public void onTileRemoved() throws RemoteException {
+ sendCallback("onTileRemoved");
+ }
+
+ @Override
+ public void onStartListening() throws RemoteException {
+ sendCallback("onStartListening");
+ }
+
+ @Override
+ public void onStopListening() throws RemoteException {
+ sendCallback("onStopListening");
+ }
+
+ @Override
+ public void onClick(IBinder iBinder) throws RemoteException {
+ sendCallback("onClick");
+ }
+ };
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
+ sendCallback("onCreate");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ sendCallback("onDestroy");
+ }
+
+ private void sendCallback(String callback) {
+ Log.d("TileLifecycleManager", "Relaying: " + callback);
+ sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
+ .putExtra(EXTRA_CALLBACK, callback));
+ }
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_KILL.equals(intent.getAction())) {
+ Process.killProcess(Process.myPid());
+ }
+ }
+ };
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
new file mode 100644
index 0000000..4586c28
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.service.quicksettings.TileService;
+import com.android.systemui.SysuiTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class TileServiceManagerTests extends SysuiTestCase {
+
+ private TileServices mTileServices;
+ private TileLifecycleManager mTileLifecycle;
+ private HandlerThread mThread;
+ private Handler mHandler;
+ private TileServiceManager mTileServiceManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mThread = new HandlerThread("TestThread");
+ mThread.start();
+ mHandler = new Handler(mThread.getLooper());
+ mTileServices = Mockito.mock(TileServices.class);
+ Mockito.when(mTileServices.getContext()).thenReturn(mContext);
+ mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+ ComponentName componentName = new ComponentName(mContext,
+ TileServiceManagerTests.class);
+ Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+ mContext.getSharedPreferences(TileServiceManager.PREFS_FILE, 0).edit()
+ .putInt(componentName.flattenToString(), TileService.TILE_MODE_PASSIVE).commit();
+ mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mThread.quit();
+ }
+
+ public void testSetBindRequested() {
+ // Request binding.
+ mTileServiceManager.setBindRequested(true);
+ mTileServiceManager.setLastUpdate(0);
+ mTileServiceManager.calculateBindPriority(5);
+ Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+ assertEquals(5, mTileServiceManager.getBindPriority());
+
+ // Verify same state doesn't trigger recalculating for no reason.
+ mTileServiceManager.setBindRequested(true);
+ Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+ mTileServiceManager.setBindRequested(false);
+ mTileServiceManager.calculateBindPriority(5);
+ Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+ assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+ }
+
+ public void testPendingClickPriority() {
+ Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+ mTileServiceManager.calculateBindPriority(0);
+ assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+ }
+
+ public void testBind() {
+ // Trigger binding requested and allowed.
+ mTileServiceManager.setBindRequested(true);
+ mTileServiceManager.setBindAllowed(true);
+
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+ assertTrue((boolean) captor.getValue());
+
+ mTileServiceManager.setBindRequested(false);
+ mTileServiceManager.calculateBindPriority(0);
+ // Priority shouldn't disappear after the request goes away if we just bound, instead
+ // it sticks around to avoid thrashing a bunch of processes.
+ assertEquals(Integer.MAX_VALUE - 1, mTileServiceManager.getBindPriority());
+
+ mTileServiceManager.setBindAllowed(false);
+ captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+ assertFalse((boolean) captor.getValue());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
new file mode 100644
index 0000000..7a3ce87
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Looper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+public class TileServicesTests extends SysuiTestCase {
+ private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+ private TileServices mTileService;
+ private ArrayList<TileServiceManager> mManagers;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mManagers = new ArrayList<>();
+ QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+ null, null, null, null, null, null);
+ mTileService = new TestTileServices(host, Looper.myLooper());
+ }
+
+ public void testRecalculateBindAllowance() {
+ // Add some fake tiles.
+ for (int i = 0; i < NUM_FAKES; i++) {
+ mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ }
+ assertEquals(NUM_FAKES, mManagers.size());
+
+ for (int i = 0; i < NUM_FAKES; i++) {
+ Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+ }
+ mTileService.recalculateBindAllowance();
+ for (int i = 0; i < NUM_FAKES; i++) {
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+ Mockito.anyLong());
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+ assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+ (boolean) captor.getValue());
+ }
+ }
+
+ public void testSetMemoryPressure() {
+ testRecalculateBindAllowance();
+ mTileService.setMemoryPressure(true);
+
+ for (int i = 0; i < NUM_FAKES; i++) {
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+ assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+ (boolean) captor.getValue());
+ }
+ }
+
+ public void testCalcFew() {
+ for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+ mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+ }
+ mTileService.recalculateBindAllowance();
+
+ for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+ // Shouldn't get bind prioirities calculated when there are less than the max services.
+ Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+ Mockito.anyLong());
+
+ // All should be bound since there are less than the max services.
+ ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+ Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+ assertTrue(captor.getValue());
+ }
+ }
+
+ private class TestTileServices extends TileServices {
+ public TestTileServices(QSTileHost host, Looper looper) {
+ super(host, looper);
+ }
+
+ @Override
+ protected TileServiceManager onCreateTileService(ComponentName component) {
+ TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+ mManagers.add(manager);
+ return manager;
+ }
+ }
+}
diff --git a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..173cd03
--- /dev/null
+++ b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,29 @@
+<?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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="prompt" msgid="3183836924226407828">"Zahtev za povezivanje"</string>
+ <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> želi da podesi VPN vezu koja omogućava praćenje saobraćaja na mreži. Prihvatite samo ako verujete izvoru. <br /> <br /> <img src=vpn_icon /> se prikazuje u vrhu ekrana kada je VPN aktivan."</string>
+ <string name="legacy_title" msgid="192936250066580964">"VPN je povezan"</string>
+ <string name="configure" msgid="4905518375574791375">"Konfiguriši"</string>
+ <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
+ <string name="session" msgid="6470628549473641030">"Sesija:"</string>
+ <string name="duration" msgid="3584782459928719435">"Trajanje:"</string>
+ <string name="data_transmitted" msgid="7988167672982199061">"Poslato:"</string>
+ <string name="data_received" msgid="4062776929376067820">"Primljeno:"</string>
+ <string name="data_value_format" msgid="2192466557826897580">"<xliff:g id="NUMBER_0">%1$s</xliff:g> bajt(ov)a / <xliff:g id="NUMBER_1">%2$s</xliff:g> paketa"</string>
+</resources>
diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml
index e438c84..0f9e247 100644
--- a/packages/WallpaperCropper/res/values/styles.xml
+++ b/packages/WallpaperCropper/res/values/styles.xml
@@ -15,7 +15,7 @@
-->
<resources>
- <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.DayNight">
+ <style name="Theme.WallpaperCropper" parent="@*android:style/Theme.Material.DayNight">
<item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowActionBarOverlay">true</item>
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 25fef18..6f8f8eb 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.appwidget;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -37,6 +38,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -44,7 +46,10 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Point;
+import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -72,6 +77,7 @@
import android.view.WindowManager;
import android.widget.RemoteViews;
+import com.android.internal.R;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
@@ -134,8 +140,10 @@
private static final int CURRENT_VERSION = 1;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (DEBUG) {
Slog.i(TAG, "Received broadcast: " + action);
@@ -143,15 +151,16 @@
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
onConfigurationChanged();
- } else if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL));
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ onUserUnlocked(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL));
+ onUserStopped(userId);
+ } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
+ refreshProfileWidgetsMaskedState(userId);
+ } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
+ refreshWidgetMaskedState(userId);
} else {
- onPackageBroadcastReceived(intent, intent.getIntExtra(
- Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
+ onPackageBroadcastReceived(intent, userId);
}
}
};
@@ -208,6 +217,7 @@
mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
mBackupRestoreController = new BackupRestoreController();
mSecurityPolicy = new SecurityPolicy();
+
computeMaximumWidgetBitmapMemory();
registerBroadcastReceiver();
registerOnCrossProfileProvidersChangedListener();
@@ -249,10 +259,16 @@
sdFilter, null, null);
IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_STARTED);
+ userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
userFilter.addAction(Intent.ACTION_USER_STOPPED);
+ userFilter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
userFilter, null, null);
+
+ IntentFilter offModeFilter = new IntentFilter();
+ offModeFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
+ mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+ offModeFilter, null, null);
}
private void registerOnCrossProfileProvidersChangedListener() {
@@ -320,6 +336,8 @@
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
+ if (!mUserManager.isUserUnlocked(userId)) return;
+
final String action = intent.getAction();
boolean added = false;
boolean changed = false;
@@ -395,6 +413,59 @@
}
}
+ /**
+ * Refresh the masked state for all profiles under the given user.
+ */
+ private void refreshProfileWidgetsMaskedState(int userId) {
+ if (!mUserManager.isUserUnlocked(userId)) return;
+ List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
+ if (profiles != null) {
+ for (int i = 0; i < profiles.size(); i++) {
+ UserInfo user = profiles.get(i);
+ refreshWidgetMaskedState(user.id);
+ }
+ }
+ }
+
+ /**
+ * Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
+ */
+ private void refreshWidgetMaskedState(int profileId) {
+ if (!mUserManager.isUserUnlocked(profileId)) return;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo user = mUserManager.getUserInfo(profileId);
+ if (!user.isManagedProfile()) {
+ return;
+ }
+ boolean shouldMask = user.isQuietModeEnabled();
+ final int iconSize = (int) mContext.getResources().getDimension(
+ android.R.dimen.app_icon_size);
+ synchronized (mLock) {
+ final int N = mProviders.size();
+ for (int i = 0; i < N; i++) {
+ Provider provider = mProviders.get(i);
+ int providerUserId = provider.getUserId();
+ if (providerUserId == profileId) {
+ final int widgetCount = provider.widgets.size();
+ for (int j = 0; j < widgetCount; j++) {
+ Widget widget = provider.widgets.get(j);
+ if (shouldMask) {
+ widget.replaceWithMaskedViewsLocked(mContext, iconSize);
+ } else {
+ widget.clearMaskedViewsLocked();
+ }
+ scheduleNotifyUpdateAppWidgetLocked(widget,
+ widget.getEffectiveViewsLocked());
+ }
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private void resolveHostUidLocked(String pkg, int uid) {
final int N = mHosts.size();
for (int i = 0; i < N; i++) {
@@ -410,6 +481,11 @@
}
private void ensureGroupStateLoadedLocked(int userId) {
+ if (!mUserManager.isUserUnlocked(userId)) {
+ throw new IllegalStateException(
+ "User " + userId + " must be unlocked for widgets to be available");
+ }
+
final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
// Careful lad, we may have already loaded the state for some
@@ -516,7 +592,7 @@
for (int i = 0; i < N; i++) {
Widget widget = instances.get(i);
updatedIds[i] = widget.appWidgetId;
- updatedViews.add(cloneIfLocalBinder(widget.views));
+ updatedViews.add(cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
}
return updatedIds;
@@ -1128,7 +1204,7 @@
Binder.getCallingUid(), callingPackage);
if (widget != null) {
- return cloneIfLocalBinder(widget.views);
+ return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
}
return null;
@@ -1554,8 +1630,7 @@
// For a full update we replace the RemoteViews completely.
widget.views = views;
}
-
- scheduleNotifyUpdateAppWidgetLocked(widget, views);
+ scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
}
}
@@ -2248,7 +2323,7 @@
}
}
- private void onUserStarted(int userId) {
+ private void onUserUnlocked(int userId) {
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -3536,6 +3611,7 @@
int restoredId; // tracking & remapping any restored state
Provider provider;
RemoteViews views;
+ RemoteViews maskedViews;
Bundle options;
Host host;
@@ -3543,6 +3619,34 @@
public String toString() {
return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
}
+
+ public void replaceWithMaskedViewsLocked(Context context, int iconSize) {
+ if (maskedViews != null) {
+ return;
+ }
+ maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
+ try {
+ Drawable icon = context.getPackageManager().getApplicationIcon(
+ provider.info.provider.getPackageName());
+ final int width = iconSize;
+ final int height = iconSize;
+ Bitmap iconBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(iconBitmap);
+ icon.setBounds(0, 0, width, height);
+ icon.draw(canvas);
+ maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, iconBitmap);
+ } catch (NameNotFoundException e) {
+ Slog.e(TAG, "Fail to get application icon", e);
+ }
+ }
+
+ public void clearMaskedViewsLocked() {
+ maskedViews = null;
+ }
+
+ public RemoteViews getEffectiveViewsLocked() {
+ return maskedViews != null ? maskedViews : views;
+ }
}
/**
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f329cff..3c91423 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -268,7 +268,7 @@
int sysUiUid = -1;
try {
- sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui",
+ sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui",
UserHandle.USER_SYSTEM);
} catch (PackageManager.NameNotFoundException e) {
// Some platforms, such as wearables do not have a system ui.
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index f5ed83e..8d707d6 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1326,7 +1326,7 @@
void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName,
long duration, int userId, boolean sync, String reason) {
try {
- int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
+ int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId);
int appId = UserHandle.getAppId(uid);
addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason);
} catch (NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 04abcca..15b5502 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -2383,10 +2383,6 @@
return;
}
synchronized (mMethodMap) {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client);
- }
executeOrSendMessage(mCurMethod, mCaller.obtainMessageO(
MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId));
}
@@ -2716,9 +2712,7 @@
return true;
case MSG_SHOW_IM_SUBTYPE_ENABLER:
- args = (SomeArgs)msg.obj;
- showInputMethodAndSubtypeEnabler((String)args.arg1);
- args.recycle();
+ showInputMethodAndSubtypeEnabler((String)msg.obj);
return true;
case MSG_SHOW_IM_CONFIG:
@@ -3005,7 +2999,11 @@
if (!TextUtils.isEmpty(inputMethodId)) {
intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId);
}
- mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
+ final int userId;
+ synchronized (mMethodMap) {
+ userId = mSettings.getCurrentUserId();
+ }
+ mContext.startActivityAsUser(intent, null, UserHandle.of(userId));
}
private void showConfigureInputMethods() {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 184f890..6cccf38 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -24,6 +24,7 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
+
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -89,9 +90,6 @@
import android.util.TimeUtils;
import android.util.Xml;
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.os.SomeArgs;
@@ -106,6 +104,9 @@
import com.android.server.NativeDaemonConnector.SensitiveArg;
import com.android.server.pm.PackageManagerService;
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -807,8 +808,8 @@
// System user does not have media provider, so skip.
if (user.isSystemOnly()) continue;
- final ProviderInfo provider =
- mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
+ final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE, user.id);
if (provider != null) {
final IActivityManager am = ActivityManagerNative.getDefault();
try {
@@ -2812,9 +2813,33 @@
}
@Override
- public ParcelFileDescriptor mountAppFuse(String name) throws RemoteException {
- // TODO: Invoke vold to mount app fuse.
- throw new UnsupportedOperationException();
+ public ParcelFileDescriptor mountAppFuse(final String name) throws RemoteException {
+ try {
+ final int uid = Binder.getCallingUid();
+ final NativeDaemonEvent event =
+ mConnector.execute("appfuse", "mount", uid, name);
+ if (event.getFileDescriptors() == null) {
+ throw new RemoteException("AppFuse FD from vold is null.");
+ }
+ return ParcelFileDescriptor.fromFd(
+ event.getFileDescriptors()[0],
+ mHandler,
+ new ParcelFileDescriptor.OnCloseListener() {
+ @Override
+ public void onClose(IOException e) {
+ try {
+ final NativeDaemonEvent event = mConnector.execute(
+ "appfuse", "unmount", uid, name);
+ } catch (NativeDaemonConnectorException unmountException) {
+ Log.e(TAG, "Failed to unmount appfuse.");
+ }
+ }
+ });
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ } catch (IOException e) {
+ throw new RemoteException(e.getMessage());
+ }
}
@Override
@@ -3592,12 +3617,18 @@
}
pw.println();
- pw.println("mConnection:");
+ pw.println("mConnector:");
pw.increaseIndent();
mConnector.dump(fd, pw, args);
pw.decreaseIndent();
pw.println();
+ pw.println("mCryptConnector:");
+ pw.increaseIndent();
+ mCryptConnector.dump(fd, pw, args);
+ pw.decreaseIndent();
+
+ pw.println();
pw.print("Last maintenance: ");
pw.println(TimeUtils.formatForLogging(mLastMaintenance));
}
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index e8b90d8..1249c8c 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -94,7 +94,7 @@
PackageManager pm = mContext.getPackageManager();
int allowedUid = -1;
try {
- allowedUid = pm.getPackageUid(allowedPackage, userHandle);
+ allowedUid = pm.getPackageUidAsUser(allowedPackage, userHandle);
} catch (PackageManager.NameNotFoundException e) {
// not expected
Slog.e(TAG, "not able to find package " + allowedPackage, e);
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index 86183af..4dc46ac 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -48,6 +48,13 @@
static SystemConfig sInstance;
+ // permission flag, determines which types of configuration are allowed to be read
+ private static final int ALLOW_FEATURES = 0x01;
+ private static final int ALLOW_LIBS = 0x02;
+ private static final int ALLOW_PERMISSIONS = 0x04;
+ private static final int ALLOW_APP_CONFIGS = 0x08;
+ private static final int ALLOW_ALL = ~0;
+
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids;
@@ -161,21 +168,27 @@
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
- Environment.getRootDirectory(), "etc", "sysconfig"), false);
+ Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
- Environment.getRootDirectory(), "etc", "permissions"), false);
- // Only read features from OEM config
+ Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
+ // Allow ODM to customize system configs around libs, features and apps
+ int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
readPermissions(Environment.buildPath(
- Environment.getOemDirectory(), "etc", "sysconfig"), true);
+ Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
- Environment.getOemDirectory(), "etc", "permissions"), true);
+ Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
+ // Only allow OEM to customize features
+ readPermissions(Environment.buildPath(
+ Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
+ readPermissions(Environment.buildPath(
+ Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
}
- void readPermissions(File libraryDir, boolean onlyFeatures) {
+ void readPermissions(File libraryDir, int permissionFlag) {
// Read permissions from given directory.
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
- if (!onlyFeatures) {
+ if (permissionFlag == ALLOW_ALL) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
}
return;
@@ -203,16 +216,16 @@
continue;
}
- readPermissionsFromXml(f, onlyFeatures);
+ readPermissionsFromXml(f, permissionFlag);
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
- readPermissionsFromXml(platformFile, onlyFeatures);
+ readPermissionsFromXml(platformFile, permissionFlag);
}
}
- private void readPermissionsFromXml(File permFile, boolean onlyFeatures) {
+ private void readPermissionsFromXml(File permFile, int permissionFlag) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
@@ -242,6 +255,11 @@
+ ": found " + parser.getName() + ", expected 'permissions' or 'config'");
}
+ boolean allowAll = permissionFlag == ALLOW_ALL;
+ boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;
+ boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;
+ boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;
+ boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
@@ -249,7 +267,7 @@
}
String name = parser.getName();
- if ("group".equals(name) && !onlyFeatures) {
+ if ("group".equals(name) && allowAll) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = android.os.Process.getGidForName(gidStr);
@@ -261,7 +279,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("permission".equals(name) && !onlyFeatures) {
+ } else if ("permission".equals(name) && allowPermissions) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<permission> without name in " + permFile + " at "
@@ -272,7 +290,7 @@
perm = perm.intern();
readPermission(parser, perm);
- } else if ("assign-permission".equals(name) && !onlyFeatures) {
+ } else if ("assign-permission".equals(name) && allowPermissions) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
@@ -304,7 +322,7 @@
perms.add(perm);
XmlUtils.skipCurrentTag(parser);
- } else if ("library".equals(name) && !onlyFeatures) {
+ } else if ("library".equals(name) && allowLibs) {
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
@@ -320,7 +338,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("feature".equals(name)) {
+ } else if ("feature".equals(name) && allowFeatures) {
String fname = parser.getAttributeValue(null, "name");
boolean allowed;
if (!lowRam) {
@@ -341,7 +359,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("unavailable-feature".equals(name)) {
+ } else if ("unavailable-feature".equals(name) && allowFeatures) {
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
@@ -352,7 +370,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("allow-in-power-save-except-idle".equals(name) && !onlyFeatures) {
+ } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<allow-in-power-save-except-idle> without package in "
@@ -363,7 +381,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
+ } else if ("allow-in-power-save".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
@@ -374,7 +392,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
+ } else if ("fixed-ime-app".equals(name) && allowAll) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
@@ -385,7 +403,7 @@
XmlUtils.skipCurrentTag(parser);
continue;
- } else if ("app-link".equals(name)) {
+ } else if ("app-link".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<app-link> without package in " + permFile + " at "
@@ -394,7 +412,7 @@
mLinkedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
- } else if ("system-user-whitelisted-app".equals(name)) {
+ } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
@@ -403,7 +421,7 @@
mSystemUserWhitelistedApps.add(pkgname);
}
XmlUtils.skipCurrentTag(parser);
- } else if ("system-user-blacklisted-app".equals(name)) {
+ } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) {
String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) {
Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index ca5212a..aa99442 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -37,7 +37,9 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -82,6 +84,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
+import com.android.server.LocalServices;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -830,7 +833,8 @@
throw new SecurityException(msg);
}
- if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
+ if (!canUserModifyAccounts(userId, callingUid) ||
+ !canUserModifyAccountsForType(userId, account.type, callingUid)) {
return false;
}
@@ -1259,7 +1263,7 @@
account.type);
throw new SecurityException(msg);
}
- if (!canUserModifyAccounts(userId)) {
+ if (!canUserModifyAccounts(userId, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User cannot modify accounts");
@@ -1267,7 +1271,7 @@
}
return;
}
- if (!canUserModifyAccountsForType(userId, account.type)) {
+ if (!canUserModifyAccountsForType(userId, account.type, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -1321,9 +1325,6 @@
throw new SecurityException(msg);
}
UserAccounts accounts = getUserAccountsForCaller();
- if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
- return false;
- }
logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
long identityToken = clearCallingIdentity();
try {
@@ -2146,8 +2147,9 @@
if (accountType == null) throw new IllegalArgumentException("accountType is null");
// Is user disallowed from modifying accounts?
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2156,7 +2158,7 @@
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2168,7 +2170,6 @@
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2230,7 +2231,7 @@
}
// Is user disallowed from modifying accounts?
- if (!canUserModifyAccounts(userId)) {
+ if (!canUserModifyAccounts(userId, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2239,7 +2240,7 @@
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, callingUid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2310,8 +2311,9 @@
throw new IllegalArgumentException("accountType is null");
}
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2320,7 +2322,7 @@
showCantAddAccount(AccountManager.ERROR_CODE_USER_RESTRICTED, userId);
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
try {
response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
"User cannot modify accounts of this type (policy).");
@@ -2332,7 +2334,6 @@
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
@@ -2497,8 +2498,9 @@
throw new IllegalArgumentException("sessionBundle is empty");
}
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ if (!canUserModifyAccounts(userId, uid)) {
sendErrorResponse(response,
AccountManager.ERROR_CODE_USER_RESTRICTED,
"User is not allowed to add an account!");
@@ -2507,7 +2509,6 @@
}
final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
final Bundle decryptedBundle;
final String accountType;
// First decrypt session bundle to get account type for checking permission.
@@ -2554,7 +2555,7 @@
return;
}
- if (!canUserModifyAccountsForType(userId, accountType)) {
+ if (!canUserModifyAccountsForType(userId, accountType, uid)) {
sendErrorResponse(
response,
AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
@@ -4319,7 +4320,11 @@
}
}
- private boolean canUserModifyAccounts(int userId) {
+ private boolean canUserModifyAccounts(int userId, int callingUid) {
+ // the managing app can always modify accounts
+ if (isProfileOwner(callingUid)) {
+ return true;
+ }
if (getUserManager().getUserRestrictions(new UserHandle(userId))
.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
return false;
@@ -4327,7 +4332,11 @@
return true;
}
- private boolean canUserModifyAccountsForType(int userId, String accountType) {
+ private boolean canUserModifyAccountsForType(int userId, String accountType, int callingUid) {
+ // the managing app can always modify accounts
+ if (isProfileOwner(callingUid)) {
+ return true;
+ }
DevicePolicyManager dpm = (DevicePolicyManager) mContext
.getSystemService(Context.DEVICE_POLICY_SERVICE);
String[] typesArray = dpm.getAccountTypesWithManagementDisabledAsUser(userId);
@@ -4342,6 +4351,13 @@
return true;
}
+ private boolean isProfileOwner(int uid) {
+ final DevicePolicyManagerInternal dpmi =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ return (dpmi != null)
+ && dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+
@Override
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
throws RemoteException {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4348913..9dda321 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1244,7 +1244,7 @@
sInfo.applicationInfo.uid, sInfo.packageName, callingPid);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background execution not allowed: service "
- + r.intent + " to " + name.flattenToShortString()
+ + service + " to " + name.flattenToShortString()
+ " from pid=" + callingPid + " uid=" + callingUid
+ " pkg=" + callingPackage);
return null;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index be1fd58..91706f8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -53,6 +53,7 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.pm.Installer;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.AppTransition;
import com.android.server.wm.WindowManagerService;
@@ -243,6 +244,7 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -252,9 +254,11 @@
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
@@ -322,6 +326,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -491,7 +496,10 @@
// Used to indicate that a task is removed it should also be removed from recents.
private static final boolean REMOVE_FROM_RECENTS = true;
// Used to indicate that an app transition should be animated.
- private static final boolean ANIMATE = true;
+ static final boolean ANIMATE = true;
+
+ // Determines whether to take full screen screenshots
+ static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
private static native int nativeMigrateToBoost();
private static native int nativeMigrateFromBoost();
@@ -506,6 +514,8 @@
/** Run all ActivityStacks through this */
ActivityStackSupervisor mStackSupervisor;
+ ActivityStarter mActivityStarter;
+
/** Task stack change listeners. */
private RemoteCallbackList<ITaskStackListener> mTaskStackListeners =
new RemoteCallbackList<ITaskStackListener>();
@@ -1276,7 +1286,8 @@
boolean mAlwaysFinishActivities = false;
boolean mForceResizableActivities;
boolean mSupportsFreeformWindowManagement;
- boolean mTakeFullscreenScreenshots;
+ boolean mSupportsPictureInPicture;
+ Rect mDefaultPinnedStackBounds;
IActivityController mController = null;
String mProfileApp = null;
ProcessRecord mProfileProc = null;
@@ -1434,6 +1445,9 @@
static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59;
static final int IDLE_UIDS_MSG = 60;
static final int SYSTEM_USER_UNLOCK_MSG = 61;
+ static final int LOG_STACK_STATE = 62;
+ static final int VR_MODE_CHANGE_MSG = 63;
+ static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1780,7 +1794,7 @@
} break;
case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
synchronized (ActivityManagerService.this) {
- mStackSupervisor.doPendingActivityLaunchesLocked(true);
+ mActivityStarter.doPendingActivityLaunchesLocked(true);
}
} break;
case KILL_APPLICATION_MSG: {
@@ -1987,9 +2001,7 @@
}
case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
synchronized (ActivityManagerService.this) {
- int i = mTaskStackListeners.beginBroadcast();
- while (i > 0) {
- i--;
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
try {
// Make a one-way callback to the listener
mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
@@ -2001,6 +2013,20 @@
}
break;
}
+ case NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG: {
+ synchronized (ActivityManagerService.this) {
+ for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+ try {
+ // Make a one-way callback to the listener
+ mTaskStackListeners.getBroadcastItem(i).onActivityPinned();
+ } catch (RemoteException e){
+ // Handled by the RemoteCallbackList
+ }
+ }
+ mTaskStackListeners.finishBroadcast();
+ }
+ break;
+ }
case NOTIFY_CLEARTEXT_NETWORK_MSG: {
final int uid = msg.arg1;
final byte[] firstPacket = (byte[]) msg.obj;
@@ -2143,6 +2169,15 @@
case IDLE_UIDS_MSG: {
idleUids();
} break;
+ case LOG_STACK_STATE: {
+ synchronized (ActivityManagerService.this) {
+ mStackSupervisor.logStackState();
+ }
+ } break;
+ case VR_MODE_CHANGE_MSG: {
+ VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class);
+ vrService.setVrMode(msg.arg1 != 0);
+ } break;
}
}
};
@@ -2279,6 +2314,7 @@
public void setWindowManager(WindowManagerService wm) {
mWindowManager = wm;
mStackSupervisor.setWindowManager(wm);
+ mActivityStarter.setWindowManager(wm);
}
public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {
@@ -2466,6 +2502,7 @@
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
mRecentTasks = new RecentTasks(this);
mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
+ mActivityStarter = new ActivityStarter(this, mStackSupervisor);
mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);
mProcessCpuThread = new Thread("CpuTracker") {
@@ -2721,9 +2758,15 @@
return mAppBindArgs;
}
- final void setFocusedActivityLocked(ActivityRecord r, String reason) {
+ boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
if (r == null || mFocusedActivity == r) {
- return;
+ return false;
+ }
+
+ if (!r.isFocusable()) {
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+ "setFocusedActivityLocked: unfocusable r=" + r);
+ return false;
}
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
@@ -2761,10 +2804,11 @@
finishVoiceTask(last.task.voiceSession);
}
}
- if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+ if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
mWindowManager.setFocusedApp(r.appToken, true);
}
applyUpdateLockStateLocked(r);
+ applyUpdateVrModeLocked(r);
if (mFocusedActivity.userId != mLastFocusedUserId) {
mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
mHandler.obtainMessage(
@@ -2776,23 +2820,35 @@
mFocusedActivity == null ? -1 : mFocusedActivity.userId,
mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
reason);
+ return true;
}
- final void clearFocusedActivity(ActivityRecord r) {
- if (mFocusedActivity == r) {
- ActivityStack stack = mStackSupervisor.getFocusedStack();
- if (stack != null) {
- ActivityRecord top = stack.topActivity();
- if (top != null && top.userId != mLastFocusedUserId) {
- mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
- top.userId, 0));
- mLastFocusedUserId = top.userId;
- }
- }
- mFocusedActivity = null;
- EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
+ final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
+ if (mFocusedActivity != goingAway) {
+ return;
}
+
+ final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+ if (focusedStack != null) {
+ final ActivityRecord top = focusedStack.topActivity();
+ if (top != null && top.userId != mLastFocusedUserId) {
+ mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+ mHandler.sendMessage(
+ mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
+ mLastFocusedUserId = top.userId;
+ }
+ }
+
+ // Try to move focus to another activity if possible.
+ if (setFocusedActivityLocked(
+ focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
+ return;
+ }
+
+ if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
+ + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
+ mFocusedActivity = null;
+ EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
}
@Override
@@ -2804,7 +2860,7 @@
ActivityRecord r = stack.topRunningActivityLocked();
if (r != null) {
setFocusedActivityLocked(r, "setFocusedStack");
- mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -2821,7 +2877,7 @@
ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
setFocusedActivityLocked(r, "setFocusedTask");
- mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -2833,7 +2889,8 @@
/** Sets the task stack listener that gets callbacks when a task stack changes. */
@Override
public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
- synchronized (ActivityManagerService.this) {
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "registerTaskStackListener()");
+ synchronized (this) {
if (listener != null) {
mTaskStackListeners.register(listener);
}
@@ -2861,6 +2918,11 @@
mHandler.obtainMessage(IMMERSIVE_MODE_LOCK_MSG, (nextState) ? 1 : 0, 0, r));
}
+ final void applyUpdateVrModeLocked(ActivityRecord r) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(VR_MODE_CHANGE_MSG, (r.isVrActivity) ? 1 : 0, 0));
+ }
+
final void showAskCompatModeDialogLocked(ActivityRecord r) {
Message msg = Message.obtain();
msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG;
@@ -3562,6 +3624,7 @@
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
@@ -3590,7 +3653,7 @@
aInfo.applicationInfo.uid, true);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
- mStackSupervisor.startHomeActivity(intent, aInfo, reason);
+ mActivityStarter.startHomeActivityLocked(intent, aInfo, reason);
}
}
@@ -3668,9 +3731,9 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
- mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo,
- null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, false, false,
- null, null, null);
+ mActivityStarter.startActivityLocked(null, intent, null /*ephemeralIntent*/,
+ null, ri.activityInfo, null /*rInfo*/, null, null, null, null, 0, 0, 0,
+ null, 0, 0, 0, null, false, false, null, null, null);
}
}
}
@@ -3995,6 +4058,25 @@
UserHandle.getCallingUserId());
}
+ final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
+ enforceNotIsolatedCaller("ActivityContainer.startActivity");
+ final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
+ ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
+
+ // TODO: Switch to user app stacks here.
+ String mimeType = intent.getType();
+ final Uri data = intent.getData();
+ if (mimeType == null && data != null && "content".equals(data.getScheme())) {
+ mimeType = getProviderMimeType(data, userId);
+ }
+ container.checkEmbeddedAllowedInner(userId, intent, mimeType);
+
+ intent.addFlags(FORCE_NEW_TASK_FLAGS);
+ return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
+ null, 0, 0, null, null, null, null, false, userId, container, null);
+ }
+
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
@@ -4003,7 +4085,7 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
- return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+ return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);
}
@@ -4066,7 +4148,7 @@
// TODO: Switch to user app stacks here.
try {
- int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent,
+ int ret = mActivityStarter.startActivityMayWait(null, targetUid, targetPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null,
null, null, bOptions, ignoreTargetSecurity, userId, null, null);
return ret;
@@ -4095,7 +4177,7 @@
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
- mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
+ mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null,
bOptions, false, userId, null, null);
return res;
@@ -4109,7 +4191,7 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
- int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
+ int ret = mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, config, bOptions, false, userId, null, null);
return ret;
@@ -4167,7 +4249,7 @@
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startVoiceActivity", null);
// TODO: Switch to user app stacks here.
- return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent,
+ return mActivityStarter.startActivityMayWait(null, callingUid, callingPackage, intent,
resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null,
null, bOptions, false, userId, null, null);
}
@@ -4278,10 +4360,11 @@
}
final long origId = Binder.clearCallingIdentity();
- int res = mStackSupervisor.startActivityLocked(r.app.thread, intent,
- r.resolvedType, aInfo, null, null, resultTo != null ? resultTo.appToken : null,
- resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage,
- -1, r.launchedFromUid, 0, options, false, false, null, null, null);
+ int res = mActivityStarter.startActivityLocked(r.app.thread, intent,
+ null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
+ null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
+ r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
+ false, false, null, null, null);
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@@ -4293,7 +4376,7 @@
}
@Override
- public final int startActivityFromRecents(int taskId, int launchStackId, Bundle bOptions) {
+ public final int startActivityFromRecents(int taskId, Bundle bOptions) {
if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: startActivityFromRecents called without " +
START_TASKS_FROM_RECENTS;
@@ -4302,24 +4385,28 @@
}
final long origId = Binder.clearCallingIdentity();
try {
- return startActivityFromRecentsInner(taskId, launchStackId, bOptions);
+ return startActivityFromRecentsInner(taskId, bOptions);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
- final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle bOptions) {
+ final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
final TaskRecord task;
final int callingUid;
final String callingPackage;
final Intent intent;
final int userId;
synchronized (this) {
+ final ActivityOptions activityOptions = (bOptions != null)
+ ? new ActivityOptions(bOptions) : null;
+ final int launchStackId = (activityOptions != null)
+ ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
+
if (launchStackId == HOME_STACK_ID) {
throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
+ taskId + " can't be launch in the home stack.");
}
-
task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
if (task == null) {
throw new IllegalArgumentException(
@@ -4327,10 +4414,9 @@
}
if (launchStackId != INVALID_STACK_ID) {
- if (launchStackId == DOCKED_STACK_ID && bOptions != null) {
- ActivityOptions activityOptions = new ActivityOptions(bOptions);
- mWindowManager.setDockedStackCreateState(activityOptions.getDockCreateMode(),
- null /* initialBounds */);
+ if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
+ mWindowManager.setDockedStackCreateState(
+ activityOptions.getDockCreateMode(), null /* initialBounds */);
}
if (task.stack.mStackId != launchStackId) {
mStackSupervisor.moveTaskToStackLocked(
@@ -4339,7 +4425,10 @@
}
}
- if (task.getRootActivity() != null) {
+ // If the user must confirm credentials (e.g. when first launching a work app and the
+ // Work Challenge is present) let startActivityInPackage handle the intercepting.
+ if (!mUserController.shouldConfirmCredentials(task.userId)
+ && task.getRootActivity() != null) {
moveTaskToFrontLocked(task.taskId, 0, bOptions);
return ActivityManager.START_TASK_TO_FRONT;
}
@@ -4362,7 +4451,7 @@
userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
// TODO: Switch to user app stacks here.
- int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent,
+ int ret = mActivityStarter.startActivityMayWait(null, uid, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
null, null, null, bOptions, false, userId, container, inTask);
return ret;
@@ -4376,7 +4465,7 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
- int ret = mStackSupervisor.startActivities(caller, -1, callingPackage, intents,
+ int ret = mActivityStarter.startActivities(caller, -1, callingPackage, intents,
resolvedTypes, resultTo, bOptions, userId);
return ret;
}
@@ -4388,7 +4477,7 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityInPackage", null);
// TODO: Switch to user app stacks here.
- int ret = mStackSupervisor.startActivities(null, uid, callingPackage, intents, resolvedTypes,
+ int ret = mActivityStarter.startActivities(null, uid, callingPackage, intents, resolvedTypes,
resultTo, bOptions, userId);
return ret;
}
@@ -4424,7 +4513,7 @@
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r, false)) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
Binder.restoreCallingIdentity(origId);
@@ -4762,12 +4851,11 @@
finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
}
- if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
- // If there was nothing to resume, and we are not already
- // restarting this process, but there is a visible activity that
- // is hosted by the process... then make sure all visible
- // activities are running, taking care of restarting this
- // process.
+ if (!restarting && hasVisibleActivities
+ && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+ // If there was nothing to resume, and we are not already restarting this process, but
+ // there is a visible activity that is hosted by the process... then make sure all
+ // visible activities are running, taking care of restarting this process.
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
}
@@ -5824,7 +5912,7 @@
// Clean-up disabled activities.
if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
packageName, disabledClasses, true, false, userId) && mBooted) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mStackSupervisor.scheduleIdleLocked();
}
@@ -6012,7 +6100,7 @@
}
}
if (mBooted) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mStackSupervisor.scheduleIdleLocked();
}
}
@@ -6687,6 +6775,15 @@
}
@Override
+ public final void activityRelaunched(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ synchronized (this) {
+ mStackSupervisor.activityRelaunchedLocked(token);
+ }
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ @Override
public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
@@ -7160,24 +7257,68 @@
@Override
public boolean inMultiWindowMode(IBinder token) {
- synchronized(this) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r == null) {
- return false;
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ return false;
+ }
+ // An activity is consider to be in multi-window mode if its task isn't fullscreen.
+ return !r.task.mFullscreen;
}
- // An activity is consider to be in multi-window mode if its task isn't fullscreen.
- return !r.task.mFullscreen;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
@Override
public boolean inPictureInPictureMode(IBinder token) {
- synchronized(this) {
- final ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack == null) {
- return false;
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ final ActivityStack stack = ActivityRecord.getStackLocked(token);
+ if (stack == null) {
+ return false;
+ }
+ return stack.mStackId == PINNED_STACK_ID;
}
- return stack.mStackId == PINNED_STACK_ID;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void enterPictureInPictureMode(IBinder token) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized(this) {
+ if (!mSupportsPictureInPicture) {
+ throw new IllegalStateException("enterPictureInPictureMode: "
+ + "Device doesn't support picture-in-picture mode.");
+ }
+
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+
+ if (r == null) {
+ throw new IllegalStateException("enterPictureInPictureMode: "
+ + "Can't find activity for token=" + token);
+ }
+
+ if (!r.supportsPictureInPicture()) {
+ throw new IllegalArgumentException("enterPictureInPictureMode: "
+ + "Picture-In-Picture not supported for r=" + r);
+ }
+
+ // Use the default launch bounds for pinned stack if it doesn't exist yet.
+ final Rect bounds = (mStackSupervisor.getStack(PINNED_STACK_ID) == null)
+ ? mDefaultPinnedStackBounds : null;
+
+ mStackSupervisor.moveActivityToStackLocked(
+ r, PINNED_STACK_ID, "enterPictureInPictureMode", bounds);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
@@ -8137,6 +8278,18 @@
}
}
+ @Override
+ public IBinder getUriPermissionOwnerForActivity(IBinder activityToken) {
+ enforceNotIsolatedCaller("getUriPermissionOwnerForActivity");
+ synchronized(this) {
+ ActivityRecord r = ActivityRecord.isInStackLocked(activityToken);
+ if (r == null) {
+ throw new IllegalArgumentException("Activity does not exist; token="
+ + activityToken);
+ }
+ return r.getUriPermissionsLocked().getExternalTokenLocked();
+ }
+ }
/**
* @param uri This uri must NOT contain an embedded userId.
* @param sourceUserId The userId in which the uri is to be resolved.
@@ -8712,6 +8865,20 @@
continue;
}
}
+ if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TASKS) != 0) {
+ if (tr.stack != null && tr.stack.isDockedStack()) {
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, docked stack task: " + tr);
+ continue;
+ }
+ }
+ if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
+ if (tr.stack != null && tr.stack.isPinnedStack()) {
+ if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+ "Skipping, pinned stack task: " + tr);
+ continue;
+ }
+ }
if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
// Don't include auto remove tasks that are finished or finishing.
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
@@ -8875,15 +9042,14 @@
task.mResizeable = resizeable;
mWindowManager.setTaskResizeable(taskId, resizeable);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@Override
public void resizeTask(int taskId, Rect bounds, int resizeMode) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizeTask()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -8933,8 +9099,7 @@
@Override
public Rect getTaskBounds(int taskId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getTaskBounds()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
long ident = Binder.clearCallingIdentity();
Rect rect = new Rect();
try {
@@ -9236,8 +9401,7 @@
@Override
public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
IActivityContainerCallback callback) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "createActivityContainer()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createActivityContainer()");
synchronized (this) {
if (parentActivityToken == null) {
throw new IllegalArgumentException("parent token must not be null");
@@ -9255,8 +9419,7 @@
@Override
public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "deleteActivityContainer()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "deleteActivityContainer()");
synchronized (this) {
mStackSupervisor.deleteActivityContainer(container);
}
@@ -9264,8 +9427,7 @@
@Override
public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "createStackOnDisplay()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
synchronized (this) {
final int stackId = mStackSupervisor.getNextStackId();
final ActivityStack stack =
@@ -9325,8 +9487,7 @@
@Override
public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTaskToStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
if (stackId == HOME_STACK_ID) {
throw new IllegalArgumentException(
"moveTaskToStack: Attempt to move task " + taskId + " to home stack");
@@ -9361,8 +9522,7 @@
@Override
public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
Rect initialBounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTaskToDockedStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
@@ -9388,9 +9548,13 @@
*/
@Override
public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTopActivityToPinnedStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTopActivityToPinnedStack()");
synchronized (this) {
+ if (!mSupportsPictureInPicture) {
+ throw new IllegalStateException("moveTopActivityToPinnedStack:"
+ + "Device doesn't support picture-in-pciture mode");
+ }
+
long ident = Binder.clearCallingIdentity();
try {
return mStackSupervisor.moveTopStackActivityToPinnedStackLocked(stackId, bounds);
@@ -9402,13 +9566,31 @@
@Override
public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "resizeStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
mStackSupervisor.resizeStackLocked(
- stackId, bounds, !PRESERVE_WINDOWS, allowResizeInDockedMode);
+ stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ !PRESERVE_WINDOWS, allowResizeInDockedMode);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
+ enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+ "resizeDockedStack()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds,
+ tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds,
+ PRESERVE_WINDOWS);
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -9417,8 +9599,7 @@
@Override
public void positionTaskInStack(int taskId, int stackId, int position) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "positionTaskInStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
if (stackId == HOME_STACK_ID) {
throw new IllegalArgumentException(
"positionTaskInStack: Attempt to change the position of task "
@@ -9439,8 +9620,7 @@
@Override
public List<StackInfo> getAllStackInfos() {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getAllStackInfos()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9453,8 +9633,7 @@
@Override
public StackInfo getStackInfo(int stackId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getStackInfo()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9467,8 +9646,7 @@
@Override
public boolean isInHomeStack(int taskId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "getStackInfo()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9582,8 +9760,7 @@
@Override
public void startLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "startLockTaskModeOnCurrent");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
@@ -9635,8 +9812,7 @@
@Override
public void stopLockTaskModeOnCurrent() throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "stopLockTaskModeOnCurrent");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent");
long ident = Binder.clearCallingIdentity();
try {
stopLockTaskMode();
@@ -9675,9 +9851,10 @@
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
- ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager().
- queryContentProviders(app.processName, app.uid,
- STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
+ ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
+ .queryContentProviders(app.processName, app.uid,
+ STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
providers = slice != null ? slice.getList() : null;
} catch (RemoteException ex) {
}
@@ -10902,11 +11079,18 @@
/** Notifies all listeners when the task stack has changed. */
void notifyTaskStackChangedLocked() {
+ mHandler.sendEmptyMessage(LOG_STACK_STATE);
mHandler.removeMessages(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
Message nmsg = mHandler.obtainMessage(NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG);
mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
}
+ /** Notifies all listeners when an Activity is pinned. */
+ void notifyActivityPinnedLocked() {
+ mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
+ mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
+ }
+
@Override
public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -11650,6 +11834,26 @@
}
}
+ @Override
+ public void setVrMode(IBinder token, boolean enabled) {
+ if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_VR_MODE)) {
+ throw new UnsupportedOperationException("VR mode not supported on this device!");
+ }
+
+ synchronized(this) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r == null) {
+ throw new IllegalArgumentException();
+ }
+ r.isVrActivity = enabled;
+
+ // Update associated state if this activity is currently focused
+ if (r == mFocusedActivity) {
+ applyUpdateVrModeLocked(r);
+ }
+ }
+ }
+
public boolean isTopActivityImmersive() {
enforceNotIsolatedCaller("startActivity");
synchronized (this) {
@@ -12003,20 +12207,19 @@
private void retrieveSettings() {
final ContentResolver resolver = mContext.getContentResolver();
final boolean freeformWindowManagement =
- mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+ || Settings.Global.getInt(
+ resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ final boolean supportsPictureInPicture =
+ mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
- final String fsScreenshots = Settings.Secure.getString(resolver,
- "overview_fullscreen_thumbnails");
final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
final boolean alwaysFinishActivities =
Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
- final boolean takeFullscreenScreenshots = fsScreenshots != null &&
- Integer.parseInt(fsScreenshots) != 0;
final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
- final int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
final boolean forceResizable = Settings.Global.getInt(
- resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, defaultForceResizable) != 0;
+ resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
// Transfer any global setting for forcing RTL layout, into a System Property
SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
@@ -12033,21 +12236,23 @@
mAlwaysFinishActivities = alwaysFinishActivities;
mForceResizableActivities = forceResizable;
mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
- mTakeFullscreenScreenshots = takeFullscreenScreenshots;
+ mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
// This happens before any activities are started, so we can
// change mConfiguration in-place.
updateConfigurationLocked(configuration, null, true);
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Initial config: " + mConfiguration);
- }
- }
- /** Loads resources after the current configuration has been set. */
- private void loadResourcesOnSystemReady() {
- final Resources res = mContext.getResources();
- mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
- mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
- mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+ // Load resources only after the current configuration has been set.
+ final Resources res = mContext.getResources();
+ mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
+ mThumbnailWidth = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.thumbnail_width);
+ mThumbnailHeight = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.thumbnail_height);
+ mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString(
+ com.android.internal.R.string.config_defaultPictureInPictureBounds));
+ }
}
public boolean testIsSystemReady() {
@@ -12363,7 +12568,6 @@
}
retrieveSettings();
- loadResourcesOnSystemReady();
final int currentUserId;
synchronized (this) {
currentUserId = mUserController.getCurrentUserIdLocked();
@@ -12458,7 +12662,7 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
}
}
@@ -12569,10 +12773,10 @@
// annoy the user repeatedly. Unless it is persistent, since those
// processes run critical code.
removeProcessLocked(app, false, false, "crash");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return false;
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
mStackSupervisor.finishTopRunningActivityLocked(app, reason);
}
@@ -14666,7 +14870,7 @@
int dumpUid = -2;
if (dumpPackage != null) {
try {
- dumpUid = mContext.getPackageManager().getPackageUid(dumpPackage, 0);
+ dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage, 0);
} catch (NameNotFoundException e) {
dumpUid = -1;
}
@@ -16864,6 +17068,9 @@
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
int callingUid, int[] users) {
+ // TODO: come back and remove this assumption to triage all broadcasts
+ int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+
List<ResolveInfo> receivers = null;
try {
HashSet<ComponentName> singleUserReceivers = null;
@@ -16876,7 +17083,7 @@
continue;
}
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
- .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
+ .queryIntentReceivers(intent, resolvedType, pmFlags, user);
if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
// If this is not the system user, we need to check for
// any receivers that should be filtered out.
@@ -17000,6 +17207,8 @@
}
}
+ // Verify that protected broadcasts are only being sent by system code,
+ // and that system code is only sending protected broadcasts.
final String action = intent.getAction();
final boolean isProtectedBroadcast;
try {
@@ -17009,35 +17218,47 @@
return ActivityManager.BROADCAST_SUCCESS;
}
- /*
- * Prevent non-system code (defined here to be non-persistent
- * processes) from sending protected broadcasts.
- */
- int callingAppId = UserHandle.getAppId(callingUid);
- if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
- || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
- || callingAppId == Process.NFC_UID || callingUid == 0) {
- // Always okay.
+ final boolean isCallerSystem;
+ switch (UserHandle.getAppId(callingUid)) {
+ case Process.ROOT_UID:
+ case Process.SYSTEM_UID:
+ case Process.PHONE_UID:
+ case Process.SHELL_UID:
+ case Process.BLUETOOTH_UID:
+ case Process.NFC_UID:
+ isCallerSystem = true;
+ break;
+ default:
+ isCallerSystem = (callerApp != null) && callerApp.persistent;
+ break;
+ }
- // Yell if the system is trying to send a non-protected broadcast.
- // The vast majority of broadcasts sent from system callers should
- // be protected to avoid security holes, so exceptions here should
- // be incredibly rare.
- if (!isProtectedBroadcast
- && !Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- // TODO: eventually switch over to hard throw
+ if (isCallerSystem) {
+ if (isProtectedBroadcast
+ || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+ || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
+ || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
+ || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
+ // Broadcast is either protected, or it's a public action that
+ // we've relaxed, so it's fine for system internals to send.
+ } else {
+ // The vast majority of broadcasts sent from system internals
+ // should be protected to avoid security holes, so yell loudly
+ // to ensure we examine these cases.
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system", new Throwable());
}
- } else if (callerApp == null || !callerApp.persistent) {
+ } else {
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
- } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)) {
+
+ } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
+ || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
// Special case for compatibility: we don't want apps to send this,
// but historically it has not been protected and apps may be using it
// to poke their own app widget. So, instead of making it protected,
@@ -17618,6 +17839,11 @@
"Unable to find instrumentation target package: " + ii.targetPackage);
return false;
}
+ if (!ai.hasCode()) {
+ reportStartInstrumentationFailure(watcher, className,
+ "Instrumentation target has no code: " + ii.targetPackage);
+ return false;
+ }
int match = mContext.getPackageManager().checkSignatures(
ii.targetPackage, ii.packageName);
@@ -17771,8 +17997,7 @@
@Override
public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "suppressResizeConfigChanges()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
synchronized (this) {
mSuppressResizeConfigChanges = suppress;
}
@@ -17780,8 +18005,7 @@
@Override
public void moveTasksToFullscreenStack(int fromStackId) {
- enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
- "moveTasksToFullscreenStack()");
+ enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
if (fromStackId == HOME_STACK_ID) {
throw new IllegalArgumentException("You can't move tasks from the home stack.");
}
@@ -17900,10 +18124,18 @@
EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
- if (mSupportedSystemLocales == null) {
- mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+ final Locale locale;
+ if (values.getLocales().size() == 1) {
+ // This is an optimization to avoid the JNI call when the result of
+ // getFirstMatch() does not depend on the supported locales.
+ locale = values.getLocales().getPrimary();
+ } else {
+ if (mSupportedSystemLocales == null) {
+ mSupportedSystemLocales =
+ Resources.getSystem().getAssets().getLocales();
+ }
+ locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
}
- final Locale locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
locale));
@@ -20439,8 +20671,8 @@
@Override
public boolean isUserRunning(int userId, int flags) {
- if (checkCallingPermission(INTERACT_ACROSS_USERS)
- != PackageManager.PERMISSION_GRANTED) {
+ if (userId != UserHandle.getCallingUserId() && checkCallingPermission(
+ INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: isUserRunning() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
@@ -20727,7 +20959,7 @@
public void moveToFront() {
checkCaller();
// Will bring task to front if it already has a root activity.
- startActivityFromRecentsInner(mTaskId, INVALID_STACK_ID, null);
+ startActivityFromRecentsInner(mTaskId, null);
}
@Override
@@ -20748,7 +20980,7 @@
throw new IllegalArgumentException("Bad app thread " + appThread);
}
}
- return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent,
+ return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
resolvedType, null, null, null, null, 0, 0, null, null,
null, bOptions, false, callingUser, null, tr);
}
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
new file mode 100644
index 0000000..4101dde
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -0,0 +1,75 @@
+package com.android.server.am;
+
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+
+import android.app.ActivityManager.StackId;
+import android.content.Context;
+import android.os.SystemClock;
+
+import com.android.internal.logging.MetricsLogger;
+
+/**
+ * Handles logging into Tron.
+ */
+class ActivityMetricsLogger {
+ // Window modes we are interested in logging. If we ever introduce a new type, we need to add
+ // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
+ private static final int WINDOW_STATE_STANDARD = 0;
+ private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
+ private static final int WINDOW_STATE_FREEFORM = 2;
+ private static final int WINDOW_STATE_INVALID = -1;
+
+ // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
+ // time we log.
+ private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
+ "window_time_0", "window_time_1", "window_time_2"};
+
+ private int mWindowState = WINDOW_STATE_STANDARD;
+ private long mLastLogTimeSecs;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Context mContext;
+
+ ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
+ mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
+ mSupervisor = supervisor;
+ mContext = context;
+ }
+
+ void logWindowState() {
+ final long now = SystemClock.elapsedRealtime() / 1000;
+ if (mWindowState != WINDOW_STATE_INVALID) {
+ // We log even if the window state hasn't changed, because the user might remain in
+ // home/fullscreen move forever and we would like to track this kind of behavior
+ // too.
+ MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
+ (int) (now - mLastLogTimeSecs));
+ }
+ mLastLogTimeSecs = now;
+
+ ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
+ if (stack != null && stack.isStackVisibleLocked()) {
+ mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
+ return;
+ }
+ mWindowState = WINDOW_STATE_INVALID;
+ stack = mSupervisor.getFocusedStack();
+ if (stack.mStackId == PINNED_STACK_ID) {
+ stack = mSupervisor.findStackBehind(stack);
+ }
+ if (stack.mStackId == HOME_STACK_ID
+ || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+ mWindowState = WINDOW_STATE_STANDARD;
+ } else if (stack.mStackId == DOCKED_STACK_ID) {
+ throw new IllegalStateException("Docked stack shouldn't be the focused stack, "
+ + "because it reported not being visible.");
+ } else if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+ mWindowState = WINDOW_STATE_FREEFORM;
+ } else if (StackId.isStaticStack(stack.mStackId)) {
+ throw new IllegalStateException("Unknown stack=" + stack);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d215fc6..4fb87c3 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,22 +16,25 @@
package com.android.server.am;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
+import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import android.app.ActivityManager.TaskDescription;
-import android.app.PendingIntent;
-import android.os.PersistableBundle;
-import android.os.Trace;
-
-import com.android.internal.app.ResolverActivity;
-import com.android.internal.content.ReferrerIntent;
-import com.android.internal.util.XmlUtils;
-import com.android.server.AttributeCache;
-import com.android.server.am.ActivityStack.ActivityState;
-import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
-
import android.app.ActivityOptions;
+import android.app.PendingIntent;
import android.app.ResultInfo;
import android.content.ComponentName;
import android.content.Intent;
@@ -45,9 +48,11 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.util.EventLog;
import android.util.Log;
@@ -57,9 +62,12 @@
import android.view.IApplicationToken;
import android.view.WindowManager;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.ReferrerIntent;
+import com.android.internal.util.XmlUtils;
+import com.android.server.AttributeCache;
+import com.android.server.am.ActivityStack.ActivityState;
+import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
import java.io.File;
import java.io.IOException;
@@ -69,6 +77,10 @@
import java.util.HashSet;
import java.util.Objects;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
/**
* An entry in the history stack, representing an activity.
*/
@@ -173,6 +185,7 @@
boolean forceNewConfig; // force re-create with new config next time
int launchCount; // count of launches since last state
long lastLaunchTime; // time of last lauch of this activity
+ boolean isVrActivity; // is the activity running in VR mode?
ArrayList<ActivityContainer> mChildContainers = new ArrayList<ActivityContainer>();
String stringName; // for caching of toString().
@@ -309,6 +322,7 @@
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
pw.println(activityTypeToString(mActivityType));
+ pw.print(prefix); pw.print("vrMode="); pw.println(isVrActivity);
if (displayStartTime != 0 || startTime != 0) {
pw.print(prefix); pw.print("displayStartTime=");
if (displayStartTime == 0) pw.print("0");
@@ -398,6 +412,11 @@
}
}
+ boolean isFreeform() {
+ return task != null && task.stack != null
+ && task.stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ }
+
static class Token extends IApplicationToken.Stub {
private final WeakReference<ActivityRecord> weakActivity;
private final ActivityManagerService mService;
@@ -637,6 +656,7 @@
}
immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
+ isVrActivity = (aInfo.flags & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0;
} else {
realActivity = null;
taskAffinity = null;
@@ -648,6 +668,7 @@
noDisplay = false;
mActivityType = APPLICATION_ACTIVITY_TYPE;
immersive = false;
+ isVrActivity = false;
}
}
@@ -722,6 +743,22 @@
(intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
}
+ boolean isFocusable() {
+ return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+ }
+
+ boolean isResizeable() {
+ return (info.flags & FLAG_RESIZEABLE) != 0;
+ }
+
+ boolean supportsPictureInPicture() {
+ return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+ }
+
+ boolean isAlwaysFocusable() {
+ return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
+ }
+
void makeFinishingLocked() {
if (!finishing) {
if (task != null && task.stack != null
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ca9f28e..8d9cb589 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -28,6 +28,7 @@
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.MOVING;
import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
@@ -74,7 +75,6 @@
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.util.EventLog;
-import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -519,6 +519,14 @@
return mStackId == HOME_STACK_ID;
}
+ final boolean isDockedStack() {
+ return mStackId == DOCKED_STACK_ID;
+ }
+
+ final boolean isPinnedStack() {
+ return mStackId == PINNED_STACK_ID;
+ }
+
final boolean isOnHomeDisplay() {
return isAttached() &&
mActivityContainer.mActivityDisplay.mDisplayId == Display.DEFAULT_DISPLAY;
@@ -552,7 +560,7 @@
// TODO(multi-display): Needs to also work if focus is moving to the non-home display.
if (isOnHomeDisplay()) {
- mStackSupervisor.setFocusStack(reason, this);
+ mStackSupervisor.setFocusStackUnchecked(reason, this);
}
if (task != null) {
insertTaskAtTop(task, null);
@@ -564,15 +572,25 @@
}
}
+ boolean isFocusable() {
+ if (StackId.canReceiveKeys(mStackId)) {
+ return true;
+ }
+ // The stack isn't focusable. See if its top activity is focusable to force focus on the
+ // stack.
+ final ActivityRecord r = topRunningActivityLocked();
+ return r != null && r.isFocusable();
+ }
+
final boolean isAttached() {
return mStacks != null;
}
/**
- * Returns the top activity in any existing task matching the given
- * Intent. Returns null if no such task is found.
+ * Returns the top activity in any existing task matching the given Intent in the input result.
+ * Returns null if no such task is found.
*/
- ActivityRecord findTaskLocked(ActivityRecord target) {
+ void findTaskLocked(ActivityRecord target, FindTaskResult result) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
@@ -627,10 +645,15 @@
+ taskIntent.getComponent().flattenToShortString()
+ "/aff=" + r.task.rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
- if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
+ if (!isDocument && !taskIsDocument
+ && result.r == null && task.canMatchRootAffinity()) {
if (task.rootAffinity.equals(target.taskAffinity)) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity!");
- return r;
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
+ // It is possible for multiple tasks to have the same root affinity especially
+ // if they are in separate stacks. We save off this candidate, but keep looking
+ // to see if there is a better candidate.
+ result.r = r;
+ result.matchedByRootAffinity = true;
}
} else if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
@@ -639,7 +662,9 @@
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
- return r;
+ result.r = r;
+ result.matchedByRootAffinity = false;
+ break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
@@ -647,11 +672,11 @@
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
- return r;
+ result.r = r;
+ result.matchedByRootAffinity = false;
+ break;
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
-
- return null;
}
/**
@@ -813,10 +838,9 @@
if (hasVisibleBehindActivity()) {
// Stop visible behind activity before going to sleep.
- final ActivityRecord r = mActivityContainer.mActivityDisplay.mVisibleBehindActivity;
+ final ActivityRecord r = getVisibleBehindActivity();
mStackSupervisor.mStoppingActivities.add(r);
- if (DEBUG_STATES) Slog.v(TAG_STATES,
- "Sleep still waiting to stop visible behind " + r);
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Sleep still waiting to stop visible behind " + r);
return true;
}
@@ -862,7 +886,7 @@
// When this flag is set, we currently take the fullscreen screenshot of the activity
// but scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to
// use within SystemUI while keeping memory usage low.
- if (mService.mTakeFullscreenScreenshots) {
+ if (ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS) {
w = h = -1;
scale = 0.5f;
}
@@ -903,7 +927,7 @@
if (prev == null) {
if (!resuming) {
Slog.wtf(TAG, "Trying to pause when nothing is resumed");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
@@ -994,7 +1018,7 @@
// pause, so just treat it as being paused now.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
if (!resuming) {
- mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
return false;
}
@@ -1053,7 +1077,7 @@
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
r.stopped = true;
r.state = ActivityState.STOPPED;
- if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == r) {
+ if (getVisibleBehindActivity() == r) {
mStackSupervisor.requestVisibleBehindLocked(r, false);
}
if (r.finishing) {
@@ -1061,7 +1085,7 @@
} else {
if (r.configDestroy) {
destroyActivityLocked(r, true, "stop-config");
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} else {
mStackSupervisor.updatePreviousProcessLocked(r);
}
@@ -1117,17 +1141,16 @@
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
if (!mService.isSleepingOrShuttingDown()) {
- mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
mStackSupervisor.checkReadyForSleepLocked();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
- // If there are no more activities available to run,
- // do resume anyway to start something. Also if the top
- // activity on the stack is not the just paused activity,
- // we need to go ahead and resume it to ensure we complete
- // an in-flight app switch.
- mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
+ // If there are no more activities available to run, do resume anyway to start
+ // something. Also if the top activity on the stack is not the just paused
+ // activity, we need to go ahead and resume it to ensure we complete an
+ // in-flight app switch.
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
}
@@ -1214,9 +1237,9 @@
next.returningOptions = null;
- if (mActivityContainer.mActivityDisplay.mVisibleBehindActivity == next) {
+ if (getVisibleBehindActivity() == next) {
// When resuming an activity, require it to call requestVisibleBehind() again.
- mActivityContainer.mActivityDisplay.setVisibleBehindActivity(null);
+ setVisibleBehindActivity(null);
}
}
@@ -1282,7 +1305,7 @@
return null;
}
- private ActivityStack getNextVisibleStackLocked() {
+ ActivityStack getNextFocusableStackLocked() {
ArrayList<ActivityStack> stacks = mStacks;
final ActivityRecord parent = mActivityContainer.mParentActivity;
if (parent != null) {
@@ -1291,7 +1314,7 @@
if (stacks != null) {
for (int i = stacks.size() - 1; i >= 0; --i) {
ActivityStack stack = stacks.get(i);
- if (stack != this && stack.isStackVisibleLocked()) {
+ if (stack != this && stack.isFocusable() && stack.isStackVisibleLocked()) {
return stack;
}
}
@@ -1334,7 +1357,7 @@
}
/** Returns true if the stack is considered visible. */
- private boolean isStackVisibleLocked() {
+ boolean isStackVisibleLocked() {
if (!isAttached()) {
return false;
}
@@ -1464,7 +1487,7 @@
boolean aboveTop = top != null;
final boolean stackInvisible = !isStackVisibleLocked();
boolean behindFullscreenActivity = stackInvisible;
- boolean noStackActivityResumed = (isInStackLocked(starting) == null);
+ boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1495,18 +1518,18 @@
if (r.app == null || r.app.thread == null) {
if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
- noStackActivityResumed, r)) {
+ resumeNextActivity, r)) {
if (activityNdx >= activities.size()) {
// Record may be removed if its process needs to restart.
activityNdx = activities.size() - 1;
} else {
- noStackActivityResumed = false;
+ resumeNextActivity = false;
}
}
} else if (r.visible) {
// If this activity is already visible, then there is nothing to do here.
if (handleAlreadyVisible(r)) {
- noStackActivityResumed = false;
+ resumeNextActivity = false;
}
} else {
makeVisible(starting, r);
@@ -1547,7 +1570,7 @@
}
private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
- boolean isTop, boolean noStackActivityResumed, ActivityRecord r) {
+ boolean isTop, boolean andResume, ActivityRecord r) {
// We need to make sure the app is running if it's the top, or it is just made visible from
// invisible. If the app is already visible, it must have died while it was visible. In this
// case, we'll show the dead window but will not restart the app. Otherwise we could end up
@@ -1564,7 +1587,7 @@
setVisible(r, true);
}
if (r != starting) {
- mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+ mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
return true;
}
}
@@ -1758,15 +1781,17 @@
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
+ * @param options Activity options.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
+ *
+ * NOTE: It is not safe to call this method directly as it can cause an activity in a
+ * non-focused stack to be resumed.
+ * Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
+ * right activity for the current system state.
*/
- final boolean resumeTopActivityLocked(ActivityRecord prev) {
- return resumeTopActivityLocked(prev, null);
- }
-
- final boolean resumeTopActivityLocked(ActivityRecord prev, ActivityOptions options) {
+ boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
@@ -1817,14 +1842,13 @@
if (next == null) {
// There are no more activities!
final String reason = "noMoreActivities";
- if (!mFullscreen) {
+ if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
// Try to move focus to the next visible stack with a running activity if this
// stack is not covering the entire screen.
- final ActivityStack stack = getNextVisibleStackLocked();
- if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
- return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
- }
+ return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+ mStackSupervisor.getFocusedStack(), prev, null);
}
+
// Let's just start up the Launcher...
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
@@ -2856,7 +2880,7 @@
final ActivityRecord next = topRunningActivityLocked();
final String myReason = reason + " adjustFocus";
if (next != r) {
- if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+ if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
// For freeform, docked, and pinned stacks we always keep the focus within the
// stack as long as there is a running activity in the stack that we can adjust
// focus to.
@@ -2868,8 +2892,7 @@
// For non-fullscreen stack, we want to move the focus to the next visible
// stack to prevent the home screen from moving to the top and obscuring
// other visible stacks.
- if (!mFullscreen
- && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+ if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
return;
}
// Move the home stack to the top if this stack is fullscreen or there is no
@@ -2883,24 +2906,16 @@
}
}
- final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
- if (top != null) {
- mService.setFocusedActivityLocked(top, myReason);
- }
+ mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
}
- private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
- final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
- final String myReason = reason + " adjustFocusToNextVisibleStack";
+ private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+ final ActivityStack stack = getNextFocusableStackLocked();
+ final String myReason = reason + " adjustFocusToNextFocusableStack";
if (stack == null) {
return false;
}
- final ActivityRecord top = stack.topRunningActivityLocked();
- if (top == null) {
- return false;
- }
- mService.setFocusedActivityLocked(top, myReason);
- return true;
+ return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
}
final void stopActivityLocked(ActivityRecord r) {
@@ -3210,7 +3225,7 @@
r.makeFinishingLocked();
boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
if (activityRemoved) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
"destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3223,7 +3238,7 @@
if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
mStackSupervisor.mFinishingActivities.add(r);
r.resumeKeyDispatchingLocked();
- mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return r;
}
@@ -3348,10 +3363,11 @@
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
- int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent,
- null, aInfo, null, null, parent.appToken, null,
- 0, -1, parent.launchedFromUid, parent.launchedFromPackage,
- -1, parent.launchedFromUid, 0, null, false, true, null, null, null);
+ int res = mService.mActivityStarter.startActivityLocked(srec.app.thread, destIntent,
+ null /*ephemeralIntent*/, null, aInfo, null /*rInfo*/, null, null,
+ parent.appToken, null, 0, -1, parent.launchedFromUid,
+ parent.launchedFromPackage, -1, parent.launchedFromUid, 0, null,
+ false, true, null, null, null);
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
foundParentInTask = false;
@@ -3380,7 +3396,7 @@
if (mPausingActivity == r) {
mPausingActivity = null;
}
- mService.clearFocusedActivity(r);
+ mService.resetFocusedActivityIfNeededLocked(r);
r.configDestroy = false;
r.frozenBeforeDestroy = false;
@@ -3511,7 +3527,7 @@
}
}
if (activityRemoved) {
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
}
@@ -3685,7 +3701,7 @@
removeActivityFromHistoryLocked(r, reason);
}
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -3723,7 +3739,7 @@
setVisibleBehindActivity(null);
mStackSupervisor.scheduleIdleTimeoutLocked(null);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
boolean hasVisibleBehindActivity() {
@@ -3938,7 +3954,7 @@
updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
if (VALIDATE_TOKENS) {
@@ -4001,7 +4017,7 @@
if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
- mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return true;
}
}
@@ -4056,7 +4072,7 @@
return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
}
- mStackSupervisor.resumeTopActivitiesLocked();
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
return true;
}
@@ -4298,6 +4314,7 @@
r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
!andResume, new Configuration(mService.mConfiguration),
new Configuration(r.task.mOverrideConfig), preserveWindow);
+ mStackSupervisor.activityRelaunchingLocked(r);
// Note: don't need to call pauseIfSleepingLocked() here, because
// the caller will only pass in 'andResume' if this activity is
// currently resumed, which implies we aren't sleeping.
@@ -4646,7 +4663,7 @@
// We only need to adjust focused stack if this stack is in focus.
if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
String myReason = reason + " leftTaskHistoryEmpty";
- if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+ if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
mStackSupervisor.moveHomeStackToFront(myReason);
}
}
@@ -4719,10 +4736,7 @@
private void postAddTask(TaskRecord task, ActivityStack prevStack) {
if (prevStack != null) {
- if (prevStack != this
- && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
- task.reportPictureInPictureModeChange();
- }
+ task.reportPictureInPictureModeChangeIfNeeded(prevStack);
} else if (task.voiceSession != null) {
try {
task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4736,32 +4750,28 @@
task.updateOverrideConfiguration(bounds);
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
- (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
- r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
- bounds, task.mOverrideConfig, !r.isHomeActivity());
+ (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
+ task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
+ !r.isHomeActivity(), r.isAlwaysFocusable());
mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
r.taskConfigOverride = task.mOverrideConfig;
}
- void setFocusAndResumeStateIfNeeded(
- ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
- // If the activity had focus before move focus to this stack.
- if (setFocus) {
- // If the activity owns the last resumed activity, transfer that together,
- // so that we don't resume the same activity again in the new stack.
- // Apps may depend on onResume()/onPause() being called in pairs.
- if (setResume) {
- mResumedActivity = r;
- // Move the stack in which we are placing the activity to the front. We don't use
- // ActivityManagerService.setFocusedActivityLocked, because if the activity is
- // already focused, the call will short-circuit and do nothing.
- moveToFront(reason);
- } else {
- // We need to not only move the stack to the front, but also have the activity
- // focused. This will achieve both goals.
- mService.setFocusedActivityLocked(r, reason);
- }
+ void moveToFrontAndResumeStateIfNeeded(
+ ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+ if (!moveToFront) {
+ return;
}
+
+ // If the activity owns the last resumed activity, transfer that together,
+ // so that we don't resume the same activity again in the new stack.
+ // Apps may depend on onResume()/onPause() being called in pairs.
+ if (setResume) {
+ mResumedActivity = r;
+ }
+ // Move the stack in which we are placing the activity to the front. The call will also
+ // make sure the activity focus is set.
+ moveToFront(reason);
}
/**
@@ -4785,8 +4795,11 @@
r.setTask(task, null);
task.addActivityToTop(r);
setAppTask(r, task);
- task.reportPictureInPictureModeChange();
- setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+ task.reportPictureInPictureModeChangeIfNeeded(prevStack);
+ moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+ if (wasResumed) {
+ prevStack.mResumedActivity = null;
+ }
}
private void setAppTask(ActivityRecord r, TaskRecord task) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6c00e73..4672023 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,40 +16,10 @@
package com.android.server.am;
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.app.ActivityManager.*;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStack.ActivityState.*;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-
import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityOptions;
@@ -58,12 +28,8 @@
import android.app.IActivityContainer;
import android.app.IActivityContainerCallback;
import android.app.IActivityManager;
-import android.app.IApplicationThread;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
-import android.app.ProfilerInfo;
-import android.app.ActivityManager.RunningTaskInfo;
import android.app.IActivityManager.WaitResult;
+import android.app.ProfilerInfo;
import android.app.ResultInfo;
import android.app.StatusBarManager;
import android.app.admin.IDevicePolicyManager;
@@ -71,7 +37,6 @@
import android.content.Context;
import android.content.IIntentSender;
import android.content.Intent;
-import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -86,10 +51,7 @@
import android.hardware.display.VirtualDisplay;
import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
-import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
@@ -115,18 +77,14 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
-
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.InputEvent;
import android.view.Surface;
-import com.android.internal.app.HeavyWeightSwitcherActivity;
-import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.TransferPipe;
-import com.android.internal.R;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -142,23 +100,83 @@
import java.util.List;
import java.util.Set;
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+
public final class ActivityStackSupervisor implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
- private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
- private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
- private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
- private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+ static final String TAG_TASKS = TAG + POSTFIX_TASKS;
private static final String TAG_VISIBLE_BEHIND = TAG + POSTFIX_VISIBLE_BEHIND;
- private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
/** How long we wait until giving up on the last activity telling us it is idle. */
static final int IDLE_TIMEOUT = 10 * 1000;
@@ -190,7 +208,7 @@
// Used to indicate if an object (e.g. stack) that we are trying to get
// should be created if it doesn't exist already.
- private static final boolean CREATE_IF_NEEDED = true;
+ static final boolean CREATE_IF_NEEDED = true;
// Used to indicate that windows of activities should be preserved during the resize.
static final boolean PRESERVE_WINDOWS = true;
@@ -263,14 +281,14 @@
private int mCurTaskId = 0;
/** The current user */
- private int mCurrentUser;
+ int mCurrentUser;
/** The stack containing the launcher app. Assumed to always be attached to
* Display.DEFAULT_DISPLAY. */
- private ActivityStack mHomeStack;
+ ActivityStack mHomeStack;
/** The stack currently receiving input or launching the next activity. */
- private ActivityStack mFocusedStack;
+ ActivityStack mFocusedStack;
/** If this is the same as mFocusedStack then the activity on the top of the focused stack has
* been resumed. If stacks are changing position this will hold the old stack until the new
@@ -352,9 +370,7 @@
*/
private LockTaskNotify mLockTaskNotify;
- final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
-
- /** Used to keep resumeTopActivityLocked() from being entered recursively */
+ /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
boolean inResumeTopActivity;
// temp. rects used during resize calculation so we don't need to create a new object each time.
@@ -363,6 +379,7 @@
private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+ private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
// The default minimal size that will be used if the activity doesn't specify its minimal size.
// It will be calculated when the default display gets added.
@@ -371,6 +388,16 @@
// Whether tasks have moved and we need to rank the tasks before next OOM scoring
private boolean mTaskLayersChanged = true;
+ private final ActivityMetricsLogger mActivityMetricsLogger;
+
+ private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
+
+ static class FindTaskResult {
+ ActivityRecord r;
+ boolean matchedByRootAffinity;
+ }
+ private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
+
/**
* Description of a request to start a new activity, which has been held
* due to app switches being disabled.
@@ -407,6 +434,8 @@
mService = service;
mRecentTasks = recentTasks;
mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
+ mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
+ mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
}
/**
@@ -467,8 +496,8 @@
calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
}
- createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
- mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+ mHomeStack = mFocusedStack = mLastFocusedStack =
+ getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
}
@@ -512,16 +541,30 @@
return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
}
- void setFocusStack(String reason, ActivityStack focusedStack) {
- mLastFocusedStack = mFocusedStack;
- mFocusedStack = focusedStack;
+ /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
+ void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
+ if (!focusCandidate.isFocusable()) {
+ // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
+ focusCandidate = focusCandidate.getNextFocusableStackLocked();
+ }
- EventLogTags.writeAmFocusedStack(
- mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+ if (focusCandidate != mFocusedStack) {
+ mLastFocusedStack = mFocusedStack;
+ mFocusedStack = focusCandidate;
+
+ EventLogTags.writeAmFocusedStack(
+ mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+ }
+
+ final ActivityRecord r = topRunningActivityLocked();
+ if (mService.mFocusedActivity != r) {
+ // The focus activity should always be the top activity in the focused stack.
+ // There will be chaos and anarchy if it isn't...
+ mService.setFocusedActivityLocked(r, reason + " setFocusStack");
+ }
if (mService.mBooting || !mService.mBooted) {
- final ActivityRecord r = topRunningActivityLocked();
if (r != null && r.idle) {
checkFinishBootingLocked();
}
@@ -566,12 +609,14 @@
mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
ActivityRecord r = getHomeActivity();
+ final String myReason = reason + " resumeHomeStackTask";
+
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
- mService.setFocusedActivityLocked(r, reason);
- return resumeTopActivitiesLocked(mHomeStack, prev, null);
+ mService.setFocusedActivityLocked(r, myReason);
+ return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
}
- return mService.startHomeActivityLocked(mCurrentUser, reason);
+ return mService.startHomeActivityLocked(mCurrentUser, myReason);
}
TaskRecord anyTaskForIdLocked(int id) {
@@ -868,7 +913,7 @@
final ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- if (stack != focusedStack && isFrontStack(stack)) {
+ if (stack != focusedStack && isFrontStack(stack) && stack.isFocusable()) {
r = stack.topRunningActivityLocked();
if (r != null) {
return r;
@@ -918,21 +963,9 @@
}
}
- ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
- ProfilerInfo profilerInfo, int userId) {
- // Collect information about the target of the Intent.
- ActivityInfo aInfo;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, resolvedType,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- } catch (RemoteException e) {
- aInfo = null;
- }
-
+ ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
+ ProfilerInfo profilerInfo) {
+ final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
if (aInfo != null) {
// Store the found target back into the intent, because now that
// we have it we never want to do this again. For example, if the
@@ -959,272 +992,20 @@
return aInfo;
}
- void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
- moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
- startActivityLocked(null /* caller */, intent, null /* resolvedType */, aInfo,
- null /* voiceSession */, null /* voiceInteractor */, null /* resultTo */,
- null /* resultWho */, 0 /* requestCode */, 0 /* callingPid */, 0 /* callingUid */,
- null /* callingPackage */, 0 /* realCallingPid */, 0 /* realCallingUid */,
- 0 /* startFlags */, null /* options */, false /* ignoreTargetSecurity */,
- false /* componentSpecified */,
- null /* outActivity */, null /* container */, null /* inTask */);
- if (inResumeTopActivity) {
- // If we are in resume section already, home activity will be initialized, but not
- // resumed (to avoid recursive resume) and will stay that way until something pokes it
- // again. We need to schedule another resume.
- scheduleResumeTopActivities();
- }
- }
-
- final int startActivityMayWait(IApplicationThread caller, int callingUid,
- String callingPackage, Intent intent, String resolvedType,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode, int startFlags,
- ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
- Bundle bOptions, boolean ignoreTargetSecurity, int userId,
- IActivityContainer iContainer, TaskRecord inTask) {
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- boolean componentSpecified = intent.getComponent() != null;
-
- // Don't modify the client's object!
- intent = new Intent(intent);
-
- // Collect information about the target of the Intent.
- ActivityInfo aInfo =
- resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
-
- ActivityOptions options = ActivityOptions.fromBundle(bOptions);
- ActivityContainer container = (ActivityContainer)iContainer;
- synchronized (mService) {
- if (container != null && container.mParentActivity != null &&
- container.mParentActivity.state != RESUMED) {
- // Cannot start a child activity if the parent is not resumed.
- return ActivityManager.START_CANCELED;
- }
- final int realCallingPid = Binder.getCallingPid();
- final int realCallingUid = Binder.getCallingUid();
- int callingPid;
- if (callingUid >= 0) {
- callingPid = -1;
- } else if (caller == null) {
- callingPid = realCallingPid;
- callingUid = realCallingUid;
- } else {
- callingPid = callingUid = -1;
- }
-
- final ActivityStack stack;
- if (container == null || container.mStack.isOnHomeDisplay()) {
- stack = mFocusedStack;
- } else {
- stack = container.mStack;
- }
- stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Starting activity when config will change = " + stack.mConfigWillChange);
-
- final long origId = Binder.clearCallingIdentity();
-
- if (aInfo != null &&
- (aInfo.applicationInfo.privateFlags
- &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- // This may be a heavy-weight process! Check to see if we already
- // have another, different heavy-weight process running.
- if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
- if (mService.mHeavyWeightProcess != null &&
- (mService.mHeavyWeightProcess.info.uid != aInfo.applicationInfo.uid ||
- !mService.mHeavyWeightProcess.processName.equals(aInfo.processName))) {
- int appCallingUid = callingUid;
- if (caller != null) {
- ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
- if (callerApp != null) {
- appCallingUid = callerApp.info.uid;
- } else {
- Slog.w(TAG, "Unable to find app for caller " + caller
- + " (pid=" + callingPid + ") when starting: "
- + intent.toString());
- ActivityOptions.abort(options);
- return ActivityManager.START_PERMISSION_DENIED;
- }
- }
-
- IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, "android",
- appCallingUid, userId, null, null, 0, new Intent[] { intent },
- new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
- | PendingIntent.FLAG_ONE_SHOT, null);
-
- Intent newIntent = new Intent();
- if (requestCode >= 0) {
- // Caller is requesting a result.
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
- }
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
- new IntentSender(target));
- if (mService.mHeavyWeightProcess.activities.size() > 0) {
- ActivityRecord hist = mService.mHeavyWeightProcess.activities.get(0);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
- hist.packageName);
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
- hist.task.taskId);
- }
- newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
- aInfo.packageName);
- newIntent.setFlags(intent.getFlags());
- newIntent.setClassName("android",
- HeavyWeightSwitcherActivity.class.getName());
- intent = newIntent;
- resolvedType = null;
- caller = null;
- callingUid = Binder.getCallingUid();
- callingPid = Binder.getCallingPid();
- componentSpecified = true;
- try {
- ResolveInfo rInfo =
- AppGlobals.getPackageManager().resolveIntent(
- intent, null,
- PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, userId);
- aInfo = rInfo != null ? rInfo.activityInfo : null;
- aInfo = mService.getActivityInfoForUser(aInfo, userId);
- } catch (RemoteException e) {
- aInfo = null;
- }
- }
- }
- }
-
- int res = startActivityLocked(caller, intent, resolvedType, aInfo,
- voiceSession, voiceInteractor, resultTo, resultWho,
- requestCode, callingPid, callingUid, callingPackage,
- realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
- componentSpecified, null, container, inTask);
-
- Binder.restoreCallingIdentity(origId);
-
- if (stack.mConfigWillChange) {
- // If the caller also wants to switch to a new configuration,
- // do so now. This allows a clean switch, as we are waiting
- // for the current activity to pause (so we will not destroy
- // it), and have not yet started the next activity.
- mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
- "updateConfiguration()");
- stack.mConfigWillChange = false;
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Updating to new configuration after starting activity.");
- mService.updateConfigurationLocked(config, null, false);
- }
-
- if (outResult != null) {
- outResult.result = res;
- if (res == ActivityManager.START_SUCCESS) {
- mWaitingActivityLaunched.add(outResult);
- do {
- try {
- mService.wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- } else if (res == ActivityManager.START_TASK_TO_FRONT) {
- ActivityRecord r = stack.topRunningActivityLocked();
- if (r.nowVisible && r.state == RESUMED) {
- outResult.timeout = false;
- outResult.who = new ComponentName(r.info.packageName, r.info.name);
- outResult.totalTime = 0;
- outResult.thisTime = 0;
- } else {
- outResult.thisTime = SystemClock.uptimeMillis();
- mWaitingActivityVisible.add(outResult);
- do {
- try {
- mService.wait();
- } catch (InterruptedException e) {
- }
- } while (!outResult.timeout && outResult.who == null);
- }
- }
- }
-
- return res;
- }
- }
-
- final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
- Intent[] intents, String[] resolvedTypes, IBinder resultTo,
- Bundle bOptions, int userId) {
- if (intents == null) {
- throw new NullPointerException("intents is null");
- }
- if (resolvedTypes == null) {
- throw new NullPointerException("resolvedTypes is null");
- }
- if (intents.length != resolvedTypes.length) {
- throw new IllegalArgumentException("intents are length different than resolvedTypes");
- }
-
-
- int callingPid;
- if (callingUid >= 0) {
- callingPid = -1;
- } else if (caller == null) {
- callingPid = Binder.getCallingPid();
- callingUid = Binder.getCallingUid();
- } else {
- callingPid = callingUid = -1;
- }
- final long origId = Binder.clearCallingIdentity();
+ ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
try {
- synchronized (mService) {
- ActivityRecord[] outActivity = new ActivityRecord[1];
- for (int i=0; i<intents.length; i++) {
- Intent intent = intents[i];
- if (intent == null) {
- continue;
- }
-
- // Refuse possible leaked file descriptors
- if (intent != null && intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
-
- boolean componentSpecified = intent.getComponent() != null;
-
- // Don't modify the client's object!
- intent = new Intent(intent);
-
- // Collect information about the target of the Intent.
- ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], 0, null, userId);
- // TODO: New, check if this is correct
- aInfo = mService.getActivityInfoForUser(aInfo, userId);
-
- if (aInfo != null &&
- (aInfo.applicationInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
- throw new IllegalArgumentException(
- "FLAG_CANT_SAVE_STATE not supported here");
- }
-
- ActivityOptions options = ActivityOptions.fromBundle(
- i == intents.length - 1 ? bOptions : null);
- int res = startActivityLocked(caller, intent, resolvedTypes[i],
- aInfo, null, null, resultTo, null, -1, callingPid, callingUid,
- callingPackage, callingPid, callingUid,
- 0, options, false, componentSpecified, outActivity, null, null);
- if (res < 0) {
- return res;
- }
-
- resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(origId);
+ return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
+ PackageManager.MATCH_DEFAULT_ONLY
+ | ActivityManagerService.STOCK_PM_FLAGS, userId);
+ } catch (RemoteException e) {
}
+ return null;
+ }
- return ActivityManager.START_SUCCESS;
+ ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags,
+ ProfilerInfo profilerInfo, int userId) {
+ final ResolveInfo rInfo = resolveIntent(intent, resolvedType, userId);
+ return resolveActivity(intent, rInfo, startFlags, profilerInfo);
}
final boolean realStartActivityLocked(ActivityRecord r,
@@ -1387,14 +1168,12 @@
// a resume.
stack.minimalResumeActivityLocked(r);
} else {
- // This activity is not starting in the resumed state... which
- // should look like we asked it to pause+stop (but remain visible),
- // and it has done so and reported back the current icicle and
- // other state.
+ // This activity is not starting in the resumed state... which should look like we asked
+ // it to pause+stop (but remain visible), and it has done so and reported back the
+ // current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
- "Moving to STOPPED: " + r + " (starting in stopped state)");
- r.state = STOPPED;
- r.stopped = true;
+ "Moving to PAUSED: " + r + " (starting in paused state)");
+ r.state = PAUSED;
}
// Launch the new version setup screen if needed. We do this -after-
@@ -1446,305 +1225,7 @@
"activity", r.intent.getComponent(), false, false, true);
}
- final int startActivityLocked(IApplicationThread caller,
- Intent intent, String resolvedType, ActivityInfo aInfo,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode,
- int callingPid, int callingUid, String callingPackage,
- int realCallingPid, int realCallingUid, int startFlags, ActivityOptions options,
- boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
- ActivityContainer container, TaskRecord inTask) {
- int err = ActivityManager.START_SUCCESS;
-
- ProcessRecord callerApp = null;
- if (caller != null) {
- callerApp = mService.getRecordForAppLocked(caller);
- if (callerApp != null) {
- callingPid = callerApp.pid;
- callingUid = callerApp.info.uid;
- } else {
- Slog.w(TAG, "Unable to find app for caller " + caller
- + " (pid=" + callingPid + ") when starting: "
- + intent.toString());
- err = ActivityManager.START_PERMISSION_DENIED;
- }
- }
-
- final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
-
- if (err == ActivityManager.START_SUCCESS) {
- Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
- + "} from uid " + callingUid
- + " on display " + (container == null ? (mFocusedStack == null ?
- Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
- (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
- container.mActivityDisplay.mDisplayId)));
- }
-
- ActivityRecord sourceRecord = null;
- ActivityRecord resultRecord = null;
- if (resultTo != null) {
- sourceRecord = isInAnyStackLocked(resultTo);
- if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
- "Will send result to " + resultTo + " " + sourceRecord);
- if (sourceRecord != null) {
- if (requestCode >= 0 && !sourceRecord.finishing) {
- resultRecord = sourceRecord;
- }
- }
- }
-
- final int launchFlags = intent.getFlags();
-
- if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
- // Transfer the result target from the source activity to the new
- // one being started, including any failures.
- if (requestCode >= 0) {
- ActivityOptions.abort(options);
- return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
- }
- resultRecord = sourceRecord.resultTo;
- if (resultRecord != null && !resultRecord.isInStackLocked()) {
- resultRecord = null;
- }
- resultWho = sourceRecord.resultWho;
- requestCode = sourceRecord.requestCode;
- sourceRecord.resultTo = null;
- if (resultRecord != null) {
- resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
- }
- if (sourceRecord.launchedFromUid == callingUid) {
- // The new activity is being launched from the same uid as the previous
- // activity in the flow, and asking to forward its result back to the
- // previous. In this case the activity is serving as a trampoline between
- // the two, so we also want to update its launchedFromPackage to be the
- // same as the previous activity. Note that this is safe, since we know
- // these two packages come from the same uid; the caller could just as
- // well have supplied that same package name itself. This specifially
- // deals with the case of an intent picker/chooser being launched in the app
- // flow to redirect to an activity picked by the user, where we want the final
- // activity to consider it to have been launched by the previous app activity.
- callingPackage = sourceRecord.launchedFromPackage;
- }
- }
-
- if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
- // We couldn't find a class that can handle the given Intent.
- // That's the end of that!
- err = ActivityManager.START_INTENT_NOT_RESOLVED;
- }
-
- if (err == ActivityManager.START_SUCCESS && aInfo == null) {
- // We couldn't find the specific class specified in the Intent.
- // Also the end of the line.
- err = ActivityManager.START_CLASS_NOT_FOUND;
- }
-
- if (err == ActivityManager.START_SUCCESS && sourceRecord != null
- && sourceRecord.task.voiceSession != null) {
- // If this activity is being launched as part of a voice session, we need
- // to ensure that it is safe to do so. If the upcoming activity will also
- // be part of the voice session, we can only launch it if it has explicitly
- // said it supports the VOICE category, or it is a part of the calling app.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
- && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
- try {
- intent.addCategory(Intent.CATEGORY_VOICE);
- if (!AppGlobals.getPackageManager().activitySupportsIntent(
- intent.getComponent(), intent, resolvedType)) {
- Slog.w(TAG,
- "Activity being started in current voice task does not support voice: "
- + intent);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure checking voice capabilities", e);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- }
- }
-
- if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
- // If the caller is starting a new voice session, just make sure the target
- // is actually allowing it to run this way.
- try {
- if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
- intent, resolvedType)) {
- Slog.w(TAG,
- "Activity being started in new voice task does not support: "
- + intent);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure checking voice capabilities", e);
- err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
- }
- }
-
- final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
-
- if (err != ActivityManager.START_SUCCESS) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1,
- resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- ActivityOptions.abort(options);
- return err;
- }
-
- boolean abort = !checkStartAnyActivityPermission(intent, aInfo, resultWho, requestCode,
- callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
- resultRecord, resultStack);
- abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
- callingPid, resolvedType, aInfo.applicationInfo);
-
- if (mService.mController != null) {
- try {
- // The Intent we give to the watcher has the extra data
- // stripped off, since it can contain private information.
- Intent watchIntent = intent.cloneFilter();
- abort |= !mService.mController.activityStarting(watchIntent,
- aInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- mService.mController = null;
- }
- }
-
- UserInfo user = getUserInfo(userId);
- KeyguardManager km = (KeyguardManager) mService.mContext
- .getSystemService(Context.KEYGUARD_SERVICE);
- if (user.isManagedProfile()
- && LockPatternUtils.isSeparateWorkChallengeEnabled()
- && km.isDeviceLocked(userId)) {
- IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
- new String[]{ resolvedType },
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_IMMUTABLE, null);
- int flags = intent.getFlags();
- intent = km.createConfirmDeviceCredentialIntent(null, null);
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
- intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
- intent.putExtra(Intent.EXTRA_USER_ID, userId);
- intent.setFlags(flags);
-
- resolvedType = null;
- callingUid = realCallingUid;
- callingPid = realCallingPid;
-
- UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
- aInfo = resolveActivity(intent, null, PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, null, parent.id);
- }
-
- if (abort) {
- if (resultRecord != null) {
- resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
- Activity.RESULT_CANCELED, null);
- }
- // We pretend to the caller that it was really started, but
- // they will just get a cancel result.
- ActivityOptions.abort(options);
- return ActivityManager.START_SUCCESS;
- }
-
- // If permissions need a review before any of the app components can run, we
- // launch the review activity and pass a pending intent to start the activity
- // we are to launching now after the review is completed.
- if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
- if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
- aInfo.packageName, userId)) {
- IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
- callingUid, userId, null, null, 0, new Intent[]{intent},
- new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
- | PendingIntent.FLAG_ONE_SHOT, null);
-
- Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
- newIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
- newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
- if (resultRecord != null) {
- newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
- }
- newIntent.setFlags(intent.getFlags());
- intent = newIntent;
-
- resolvedType = null;
- callingUid = realCallingUid;
- callingPid = realCallingPid;
-
- aInfo = resolveActivity(intent, null, PackageManager.MATCH_DEFAULT_ONLY
- | ActivityManagerService.STOCK_PM_FLAGS, null, userId);
-
- if (DEBUG_PERMISSIONS_REVIEW) {
- Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
- true, false) + "} from uid " + callingUid + " on display "
- + (container == null ? (mFocusedStack == null ?
- Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
- (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
- container.mActivityDisplay.mDisplayId)));
- }
- }
- }
-
- ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
- intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
- requestCode, componentSpecified, voiceSession != null, this, container, options);
- if (outActivity != null) {
- outActivity[0] = r;
- }
-
- if (r.appTimeTracker == null && sourceRecord != null) {
- // If the caller didn't specify an explicit time tracker, we want to continue
- // tracking under any it has.
- r.appTimeTracker = sourceRecord.appTimeTracker;
- }
-
- final ActivityStack stack = mFocusedStack;
- if (voiceSession == null && (stack.mResumedActivity == null
- || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
- if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
- realCallingPid, realCallingUid, "Activity start")) {
- PendingActivityLaunch pal = new PendingActivityLaunch(r,
- sourceRecord, startFlags, stack, callerApp);
- mPendingActivityLaunches.add(pal);
- ActivityOptions.abort(options);
- return ActivityManager.START_SWITCHES_CANCELED;
- }
- }
-
- if (mService.mDidAppSwitch) {
- // This is the second allowed switch since we stopped switches,
- // so now just generally allow switches. Use case: user presses
- // home (switches disabled, switch to home, mDidAppSwitch now true);
- // user taps a home icon (coming from home so allowed, we hit here
- // and now allow anyone to switch again).
- mService.mAppSwitchesAllowedTime = 0;
- } else {
- mService.mDidAppSwitch = true;
- }
-
- doPendingActivityLaunchesLocked(false);
-
- err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
- startFlags, true, options, inTask);
-
- if (err < 0) {
- // If someone asked to have the keyguard dismissed on the next
- // activity start, but we are not actually doing an activity
- // switch... just dismiss the keyguard now, because we
- // probably want to see whatever is behind it.
- notifyActivityDrawnForKeyguard();
- }
- return err;
- }
-
- private boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
+ boolean checkStartAnyActivityPermission(Intent intent, ActivityInfo aInfo,
String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, boolean ignoreTargetSecurity, ProcessRecord callerApp,
ActivityRecord resultRecord, ActivityStack resultStack) {
@@ -1804,7 +1285,7 @@
return true;
}
- private UserInfo getUserInfo(int userId) {
+ UserInfo getUserInfo(int userId) {
final long identity = Binder.clearCallingIdentity();
try {
return UserManager.get(mService.mContext).getUserInfo(userId);
@@ -1882,803 +1363,20 @@
return ACTIVITY_RESTRICTION_NONE;
}
- private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds) {
- final TaskRecord task = r.task;
-
- if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
- return mHomeStack;
- }
-
- ActivityStack stack;
-
- if (task != null && task.stack != null) {
- stack = task.stack;
- if (stack.isOnHomeDisplay()) {
- if (mFocusedStack != stack) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Setting " + "focused stack to r=" + r
- + " task=" + task);
- } else {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Focused stack already=" + mFocusedStack);
- }
- }
- return stack;
- }
-
- final ActivityContainer container = r.mInitialActivityContainer;
- if (container != null) {
- // The first time put it on the desired stack, after this put on task stack.
- r.mInitialActivityContainer = null;
- return container.mStack;
- }
-
- // The fullscreen stack can contain any task regardless of if the task is resizeable
- // or not. So, we let the task go in the fullscreen task if it is the focus stack.
- // If the freeform stack has focus, and the activity to be launched is resizeable,
- // we can also put it in the focused stack.
- final boolean canUseFocusedStack =
- mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID
- || mFocusedStack.mStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable;
- if (canUseFocusedStack
- && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Have a focused stack=" + mFocusedStack);
- return mFocusedStack;
- }
-
- // We first try to put the task in the first dynamic stack.
- final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
- for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- stack = homeDisplayStacks.get(stackNdx);
- if (!StackId.isStaticStack(stack.mStackId)) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Setting focused stack=" + stack);
- return stack;
- }
- }
-
- // If there is no suitable dynamic stack then we figure out which static stack to use.
- final int stackId = task != null ? task.getLaunchStackId() :
- bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
- FULLSCREEN_WORKSPACE_STACK_ID;
- stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
- + r + " stackId=" + stack.mStackId);
- return stack;
- }
-
- boolean setFocusedStack(ActivityRecord r, String reason) {
+ boolean moveActivityStackToFront(ActivityRecord r, String reason) {
if (r == null) {
// Not sure what you are trying to do, but it is not going to work...
return false;
}
final TaskRecord task = r.task;
if (task == null || task.stack == null) {
- Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+ Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
return false;
}
task.stack.moveToFront(reason, task);
return true;
}
- final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
- boolean doResume, ActivityOptions options, TaskRecord inTask) {
- final Intent intent = r.intent;
- final int callingUid = r.launchedFromUid;
-
- boolean overrideBounds = false;
- Rect newBounds = null;
- if (options != null && (r.info.resizeable || (inTask != null && inTask.mResizeable))) {
- if (canUseActivityOptionsLaunchBounds(options)) {
- overrideBounds = true;
- newBounds = options.getLaunchBounds();
- }
- }
-
- // In some flows in to this function, we retrieve the task record and hold on to it
- // without a lock before calling back in to here... so the task at this point may
- // not actually be in recents. Check for that, and if it isn't in recents just
- // consider it invalid.
- if (inTask != null && !inTask.inRecents) {
- Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
- inTask = null;
- }
-
- final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
- final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
- final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
-
- int launchFlags = intent.getFlags();
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
- (launchSingleInstance || launchSingleTask)) {
- // We have a conflict between the Intent and the Activity manifest, manifest wins.
- Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
- "\"singleInstance\" or \"singleTask\"");
- launchFlags &=
- ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
- } else {
- switch (r.info.documentLaunchMode) {
- case ActivityInfo.DOCUMENT_LAUNCH_NONE:
- break;
- case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- break;
- case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
- launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
- break;
- case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
- launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
- break;
- }
- }
-
- final boolean launchTaskBehind = r.mLaunchTaskBehind
- && !launchSingleTask && !launchSingleInstance
- && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
-
- if (r.resultTo != null && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
- && r.resultTo.task.stack != null) {
- // For whatever reason this activity is being launched into a new
- // task... yet the caller has requested a result back. Well, that
- // is pretty messed up, so instead immediately send back a cancel
- // and let the new task continue launched as normal without a
- // dependency on its originator.
- Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- r.resultTo.task.stack.sendActivityResultLocked(-1,
- r.resultTo, r.resultWho, r.requestCode,
- Activity.RESULT_CANCELED, null);
- r.resultTo = null;
- }
-
- if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- }
-
- // If we are actually going to launch in to a new task, there are some cases where
- // we further want to do multiple task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- if (launchTaskBehind
- || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
- launchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
- }
- }
-
- // We'll invoke onUserLeaving before onPause only if the launching
- // activity did not explicitly state that this is an automated launch.
- mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
- if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
- "startActivity() => mUserLeaving=" + mUserLeaving);
-
- // If the caller has asked not to resume at this point, we make note
- // of this in the record so that we can skip it when trying to find
- // the top running activity.
- if (!doResume || !okToShowLocked(r)) {
- r.delayedResume = true;
- doResume = false;
- }
-
- ActivityRecord notTop =
- (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
-
- // If the onlyIfNeeded flag is set, then we can do this if the activity
- // being launched is the same as the one making the call... or, as
- // a special case, if we do not know the caller then we count the
- // current top activity as the caller.
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- ActivityRecord checkedCaller = sourceRecord;
- if (checkedCaller == null) {
- checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
- }
- if (!checkedCaller.realActivity.equals(r.realActivity)) {
- // Caller is not the same as launcher, so always needed.
- startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
- }
- }
-
- boolean addingToTask = false;
- TaskRecord reuseTask = null;
-
- // If the caller is not coming from another activity, but has given us an
- // explicit task into which they would like us to launch the new activity,
- // then let's see about doing that.
- if (sourceRecord == null && inTask != null && inTask.stack != null) {
- final Intent baseIntent = inTask.getBaseIntent();
- final ActivityRecord root = inTask.getRootActivity();
- if (baseIntent == null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Launching into task without base intent: "
- + inTask);
- }
-
- // If this task is empty, then we are adding the first activity -- it
- // determines the root, and must be launching as a NEW_TASK.
- if (launchSingleInstance || launchSingleTask) {
- if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Trying to launch singleInstance/Task "
- + r + " into different task " + inTask);
- }
- if (root != null) {
- ActivityOptions.abort(options);
- throw new IllegalArgumentException("Caller with inTask " + inTask
- + " has root " + root + " but target is singleInstance/Task");
- }
- }
-
- // If task is empty, then adopt the interesting intent launch flags in to the
- // activity being started.
- if (root == null) {
- final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK
- | FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
- | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
- launchFlags = (launchFlags&~flagsOfInterest)
- | (baseIntent.getFlags()&flagsOfInterest);
- intent.setFlags(launchFlags);
- inTask.setIntent(r);
- addingToTask = true;
-
- // If the task is not empty and the caller is asking to start it as the root
- // of a new task, then we don't actually want to start this on the task. We
- // will bring the task to the front, and possibly give it a new intent.
- } else if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- addingToTask = false;
-
- } else {
- addingToTask = true;
- }
-
- reuseTask = inTask;
- } else {
- inTask = null;
- // Launch ResolverActivity in the source task, so that it stays in the task
- // bounds when in freeform workspace.
- // Also put noDisplay activities in the source task. These by itself can
- // be placed in any task/stack, however it could launch other activities
- // like ResolverActivity, and we want those to stay in the original task.
- if (r.isResolverActivity() || r.noDisplay) {
- addingToTask = true;
- }
- }
-
- if (inTask == null) {
- if (sourceRecord == null) {
- // This activity is not being started from another... in this
- // case we -always- start a new task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
- Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
- "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- }
- } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
- // The original activity who is starting us is running as a single
- // instance... this new activity it is starting must go on its
- // own task.
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- } else if (launchSingleInstance || launchSingleTask) {
- // The activity being started is a single instance... it always
- // gets launched into its own task.
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- }
- }
-
- ActivityInfo newTaskInfo = null;
- Intent newTaskIntent = null;
- ActivityStack sourceStack;
- if (sourceRecord != null) {
- if (sourceRecord.finishing) {
- // If the source is finishing, we can't further count it as our source. This
- // is because the task it is associated with may now be empty and on its way out,
- // so we don't want to blindly throw it in to that task. Instead we will take
- // the NEW_TASK flow and try to find a task for it. But save the task information
- // so it can be used when creating the new task.
- if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
- Slog.w(TAG, "startActivity called from finishing " + sourceRecord
- + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
- launchFlags |= FLAG_ACTIVITY_NEW_TASK;
- newTaskInfo = sourceRecord.info;
- newTaskIntent = sourceRecord.task.intent;
- }
- sourceRecord = null;
- sourceStack = null;
- } else {
- sourceStack = sourceRecord.task.stack;
- }
- } else {
- sourceStack = null;
- }
-
- boolean movedHome = false;
- ActivityStack targetStack;
-
- intent.setFlags(launchFlags);
- final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
-
- ActivityRecord intentActivity = getReusableIntentActivity(r, inTask, intent,
- launchSingleInstance, launchSingleTask, launchFlags);
- if (intentActivity != null) {
- // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
- // but still needs to be a lock task mode violation since the task gets
- // cleared out and the device would otherwise leave the locked task.
- if (isLockTaskModeViolation(intentActivity.task,
- (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
- showLockTaskToast();
- Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (r.task == null) {
- r.task = intentActivity.task;
- }
- if (intentActivity.task.intent == null) {
- // This task was started because of movement of the activity based on affinity...
- // Now that we are actually launching it, we can assign the base intent.
- intentActivity.task.setIntent(r);
- }
- targetStack = intentActivity.task.stack;
- targetStack.mLastPausedActivity = null;
- // If the target task is not in the front, then we need
- // to bring it to the front... except... well, with
- // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
- // to have the same behavior as if a new instance was
- // being started, which means not bringing it to the front
- // if the caller is not itself in the front.
- final ActivityStack focusStack = getFocusedStack();
- ActivityRecord curTop = (focusStack == null)
- ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
- boolean movedToFront = false;
- if (curTop != null && (curTop.task != intentActivity.task ||
- curTop.task != focusStack.topTask())) {
- r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
- if (sourceRecord == null || (sourceStack.topActivity() != null &&
- sourceStack.topActivity().task == sourceRecord.task)) {
- // We really do want to push this one into the user's face, right now.
- if (launchTaskBehind && sourceRecord != null) {
- intentActivity.setTaskToAffiliateWith(sourceRecord.task);
- }
- movedHome = true;
- targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
- options, r.appTimeTracker, "bringingFoundTaskToFront");
- movedToFront = true;
- if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
- // Caller wants to appear on home activity.
- intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
- }
- options = null;
- }
- }
- if (!movedToFront && doResume) {
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
- + " from " + intentActivity);
- targetStack.moveToFront("intentActivityFound");
- }
-
- // If the caller has requested that the target task be
- // reset, then do so.
- if ((launchFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
- intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
- }
- if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it! And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- resumeTopActivitiesLocked(targetStack, null, options);
-
- // Make sure to notify Keyguard as well if we are not running an app
- // transition later.
- if (!movedToFront) {
- notifyActivityDrawnForKeyguard();
- }
- } else {
- ActivityOptions.abort(options);
- }
- updateUserStackLocked(r.userId, targetStack);
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
- }
- if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
- // The caller has requested to completely replace any
- // existing task with its new activity. Well that should
- // not be too hard...
- reuseTask = intentActivity.task;
- reuseTask.performClearTaskLocked();
- reuseTask.setIntent(r);
- } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
- || launchSingleInstance || launchSingleTask) {
- // In this situation we want to remove all activities
- // from the task up to the one being started. In most
- // cases this means we are resetting the task to its
- // initial state.
- ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
- if (top != null) {
- if (top.frontOfTask) {
- // Activity aliases may mean we use different
- // intents for the top activity, so make sure
- // the task now has the identity of the new
- // intent.
- top.task.setIntent(r);
- }
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- } else {
- // A special case: we need to start the activity because it is not
- // currently running, and the caller has asked to clear the current
- // task to have this activity at the top.
- addingToTask = true;
- // Now pretend like this activity is being started by the top of its
- // task, so it is put in the right place.
- sourceRecord = intentActivity;
- TaskRecord task = sourceRecord.task;
- if (task != null && task.stack == null) {
- // Target stack got cleared when we all activities were removed
- // above. Go ahead and reset it.
- targetStack = computeStackFocus(
- sourceRecord, false /* newTask */, null /* bounds */);
- targetStack.addTask(task,
- !launchTaskBehind /* toTop */, "startActivityUnchecked");
- }
-
- }
- } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
- // In this case the top activity on the task is the
- // same as the one being launched, so we take that
- // as a request to bring the task to the foreground.
- // If the top activity in the task is the root
- // activity, deliver this new intent to it if it
- // desires.
- if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
- && intentActivity.realActivity.equals(r.realActivity)) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
- intentActivity.task);
- if (intentActivity.frontOfTask) {
- intentActivity.task.setIntent(r);
- }
- intentActivity.deliverNewIntentLocked(callingUid, r.intent,
- r.launchedFromPackage);
- } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
- // In this case we are launching the root activity
- // of the task, but with a different intent. We
- // should start a new instance on top.
- addingToTask = true;
- sourceRecord = intentActivity;
- }
- } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
- // In this case an activity is being launched in to an
- // existing task, without resetting that task. This
- // is typically the situation of launching an activity
- // from a notification or shortcut. We want to place
- // the new activity on top of the current task.
- addingToTask = true;
- sourceRecord = intentActivity;
- } else if (!intentActivity.task.rootWasReset) {
- // In this case we are launching in to an existing task
- // that has not yet been started from its front door.
- // The current task has been brought to the front.
- // Ideally, we'd probably like to place this new task
- // at the bottom of its stack, but that's a little hard
- // to do with the current organization of the code so
- // for now we'll just drop it.
- intentActivity.task.setIntent(r);
- }
- if (!addingToTask && reuseTask == null) {
- // We didn't do anything... but it was needed (a.k.a., client
- // don't use that intent!) And for paranoia, make
- // sure we have correctly resumed the top activity.
- if (doResume) {
- targetStack.resumeTopActivityLocked(null, options);
- if (!movedToFront) {
- // Make sure to notify Keyguard as well if we are not running an app
- // transition later.
- notifyActivityDrawnForKeyguard();
- }
- } else {
- ActivityOptions.abort(options);
- }
- updateUserStackLocked(r.userId, targetStack);
- return ActivityManager.START_TASK_TO_FRONT;
- }
- }
-
- //String uri = r.intent.toURI();
- //Intent intent2 = new Intent(uri);
- //Slog.i(TAG, "Given intent: " + r.intent);
- //Slog.i(TAG, "URI is: " + uri);
- //Slog.i(TAG, "To intent: " + intent2);
-
- if (r.packageName != null) {
- // If the activity being launched is the same as the one currently
- // at the top, then we need to check if it should only be launched
- // once.
- ActivityStack topStack = mFocusedStack;
- ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
- if (top != null && r.resultTo == null) {
- if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
- if (top.app != null && top.app.thread != null) {
- if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- || launchSingleTop || launchSingleTask) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
- top.task);
- // For paranoia, make sure we have correctly
- // resumed the top activity.
- topStack.mLastPausedActivity = null;
- if (doResume) {
- resumeTopActivitiesLocked();
- }
- ActivityOptions.abort(options);
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it!
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
- }
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- }
- }
- }
-
- } else {
- if (r.resultTo != null && r.resultTo.task.stack != null) {
- r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
- r.requestCode, Activity.RESULT_CANCELED, null);
- }
- ActivityOptions.abort(options);
- return ActivityManager.START_CLASS_NOT_FOUND;
- }
-
- boolean newTask = false;
- boolean keepCurTransition = false;
-
- TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
- sourceRecord.task : null;
-
- // Should this be considered a new task?
- if (r.resultTo == null && inTask == null && !addingToTask
- && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- newTask = true;
- targetStack = computeStackFocus(r, newTask, newBounds);
- if (doResume) {
- targetStack.moveToFront("startingNewTask");
- }
-
- if (reuseTask == null) {
- r.setTask(targetStack.createTaskRecord(getNextTaskId(),
- newTaskInfo != null ? newTaskInfo : r.info,
- newTaskIntent != null ? newTaskIntent : intent,
- voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
- taskToAffiliate);
- if (overrideBounds) {
- r.task.updateOverrideConfiguration(newBounds);
- }
- if (DEBUG_TASKS) Slog.v(TAG_TASKS,
- "Starting new activity " + r + " in new task " + r.task);
- } else {
- r.setTask(reuseTask, taskToAffiliate);
- }
- if (isLockTaskModeViolation(r.task)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (!movedHome) {
- if ((launchFlags &
- (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
- == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
- // Caller wants to appear on home activity, so before starting
- // their own activity we will bring home to the front.
- r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
- }
- }
- } else if (sourceRecord != null) {
- final TaskRecord sourceTask = sourceRecord.task;
- if (isLockTaskModeViolation(sourceTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- targetStack = sourceTask.stack;
- if (doResume) {
- targetStack.moveToFront("sourceStackToFront");
- }
- final TaskRecord topTask = targetStack.topTask();
- if (topTask != sourceTask) {
- targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
- r.appTimeTracker, "sourceTaskToFront");
- }
- if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
- // In this case, we are adding the activity to an existing
- // task, but the caller has asked to clear that task if the
- // activity is already running.
- ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
- keepCurTransition = true;
- if (top != null) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- // For paranoia, make sure we have correctly
- // resumed the top activity.
- targetStack.mLastPausedActivity = null;
- if (doResume) {
- targetStack.resumeTopActivityLocked(null);
- }
- ActivityOptions.abort(options);
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- } else if (!addingToTask &&
- (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
- // In this case, we are launching an activity in our own task
- // that may already be running somewhere in the history, and
- // we want to shuffle it to the front of the stack if so.
- final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
- if (top != null) {
- final TaskRecord task = top.task;
- task.moveActivityToFrontLocked(top);
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
- top.updateOptionsLocked(options);
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- targetStack.mLastPausedActivity = null;
- if (doResume) {
- targetStack.resumeTopActivityLocked(null);
- }
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- }
- // An existing activity is starting this new activity, so we want
- // to keep the new one in the same task as the one that is starting
- // it.
- r.setTask(sourceTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in existing task " + r.task + " from source " + sourceRecord);
-
- } else if (inTask != null) {
- // The caller is asking that the new activity be started in an explicit
- // task it has provided to us.
- if (isLockTaskModeViolation(inTask)) {
- Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
- return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
- }
- if (overrideBounds) {
- inTask.updateOverrideConfiguration(newBounds);
- int stackId = inTask.getLaunchStackId();
- if (stackId != inTask.stack.mStackId) {
- moveTaskToStackUncheckedLocked(
- inTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
- }
- }
- targetStack = inTask.stack;
- targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, r.appTimeTracker,
- "inTaskToFront");
-
- // Check whether we should actually launch the new activity in to the task,
- // or just reuse the current activity on top.
- ActivityRecord top = inTask.getTopActivity();
- if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
- if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
- || launchSingleTop || launchSingleTask) {
- ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
- if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
- // We don't need to start a new activity, and
- // the client said not to do anything if that
- // is the case, so this is it!
- return ActivityManager.START_RETURN_INTENT_TO_CALLER;
- }
- top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
- return ActivityManager.START_DELIVERED_TO_TOP;
- }
- }
-
- if (!addingToTask) {
- // We don't actually want to have this activity added to the task, so just
- // stop here but still tell the caller that we consumed the intent.
- ActivityOptions.abort(options);
- return ActivityManager.START_TASK_TO_FRONT;
- }
-
- r.setTask(inTask, null);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in explicit task " + r.task);
-
- } else {
- // This not being started from an existing activity, and not part
- // of a new task... just put it in the top task, though these days
- // this case should never happen.
- targetStack = computeStackFocus(r, newTask, null /* bounds */);
- if (doResume) {
- targetStack.moveToFront("addingToTopTask");
- }
- ActivityRecord prev = targetStack.topActivity();
- r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
- r.info, intent, null, null, true), null);
- mWindowManager.moveTaskToTop(r.task.taskId);
- if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
- + " in new guessed " + r.task);
- }
-
- mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
- intent, r.getUriPermissionsLocked(), r.userId);
-
- if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
- r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
- }
- if (newTask) {
- EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
- }
- ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
- targetStack.mLastPausedActivity = null;
- targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
- if (doResume) {
- if (!launchTaskBehind) {
- mService.setFocusedActivityLocked(r, "startedActivity");
- }
- resumeTopActivitiesLocked(targetStack, r, options);
- } else {
- targetStack.addRecentActivityLocked(r);
- }
- updateUserStackLocked(r.userId, targetStack);
-
- if (!r.task.mResizeable && isStackDockedInEffect(targetStack.mStackId)) {
- showNonResizeableDockToast(r.task.taskId);
- }
-
- return ActivityManager.START_SUCCESS;
- }
-
- /**
- * Decide whether the new activity should be inserted into an existing task. Returns null if not
- * or an ActivityRecord with the task into which the new activity should be added.
- */
- private ActivityRecord getReusableIntentActivity(ActivityRecord r, TaskRecord inTask, Intent intent,
- boolean launchSingleInstance, boolean launchSingleTask, int launchFlags) {
- // We may want to try to place the new activity in to an existing task. We always
- // do this if the target activity is singleTask or singleInstance; we will also do
- // this if NEW_TASK has been requested, and there is not an additional qualifier telling
- // us to still place it in a new task: multi task, always doc mode, or being asked to
- // launch this as a new task behind the current one.
- boolean putIntoExistingTask = ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
- (launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
- || launchSingleInstance || launchSingleTask;
- // If bring to front is requested, and no result is requested and we have not
- // been given an explicit task to launch in to, and
- // we can find a task that was started with this same
- // component, then instead of launching bring that one to the front.
- putIntoExistingTask &= inTask == null && r.resultTo == null;
- ActivityRecord intentActivity = null;
- if (putIntoExistingTask) {
- // See if there is a task to bring to the front. If this is
- // a SINGLE_INSTANCE activity, there can be one and only one
- // instance of it in the history, and it is always in its own
- // unique task, so we do a special search.
- intentActivity = launchSingleInstance ?
- findActivityLocked(intent, r.info) : findTaskLocked(r);
- }
- return intentActivity;
- }
-
- final void doPendingActivityLaunchesLocked(boolean doResume) {
- while (!mPendingActivityLaunches.isEmpty()) {
- PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
-
- try {
- startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
- doResume && mPendingActivityLaunches.isEmpty(), null, null);
- } catch (Exception e) {
- Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
- pal.sendErrorResult(e.getMessage());
- }
- }
- }
-
- void removePendingActivityLaunchesLocked(ActivityStack stack) {
- for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
- PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
- if (pal.stack == stack) {
- mPendingActivityLaunches.remove(palNdx);
- }
- }
- }
-
void setLaunchSource(int uid) {
mLaunchingActivity.setWorkSource(new WorkSource(uid));
}
@@ -2828,7 +1526,7 @@
//mWindowManager.dump();
if (activityRemoved) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
return r;
@@ -2921,35 +1619,17 @@
}
}
- boolean resumeTopActivitiesLocked() {
- return resumeTopActivitiesLocked(null, null, null);
+ boolean resumeFocusedStackTopActivityLocked() {
+ return resumeFocusedStackTopActivityLocked(null, null, null);
}
- boolean resumeTopActivitiesLocked(
+ boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
- if (targetStack == null) {
- targetStack = mFocusedStack;
+ if (targetStack != null && isFocusedStack(targetStack)) {
+ return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
- // Do targetStack first.
- boolean result = false;
- if (isFocusedStack(targetStack)) {
- result = targetStack.resumeTopActivityLocked(target, targetOptions);
- }
-
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = stacks.get(stackNdx);
- if (stack == targetStack) {
- // Already started above.
- continue;
- }
- if (isFocusedStack(stack)) {
- stack.resumeTopActivityLocked(null);
- }
- }
- }
- return result;
+ mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+ return false;
}
void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
@@ -2991,10 +1671,13 @@
}
if (task.mResizeable && options != null) {
- if (canUseActivityOptionsLaunchBounds(options)) {
+ int stackId = options.getLaunchStackId();
+ if (canUseActivityOptionsLaunchBounds(options, stackId)) {
Rect bounds = options.getLaunchBounds();
task.updateOverrideConfiguration(bounds);
- final int stackId = task.getLaunchStackId();
+ if (stackId == INVALID_STACK_ID) {
+ stackId = task.getLaunchStackId();
+ }
if (stackId != task.stack.mStackId) {
moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
// moveTaskToStackUncheckedLocked() should already placed the task on top,
@@ -3016,10 +1699,14 @@
"findTaskToMoveToFront: moved to front of stack=" + task.stack);
}
- private boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
+ boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
// We use the launch bounds in the activity options is the device supports freeform
- // window management.
- return options.hasLaunchBounds() && mService.mSupportsFreeformWindowManagement;
+ // window management or is launching into the pinned stack.
+ if (!options.hasLaunchBounds()) {
+ return false;
+ }
+ return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+ || mService.mSupportsFreeformWindowManagement;
}
ActivityStack getStack(int stackId) {
@@ -3116,16 +1803,20 @@
}
}
- void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows,
- boolean allowResizeInDockedMode) {
+ void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
+ boolean preserveWindows, boolean allowResizeInDockedMode) {
+ if (stackId == DOCKED_STACK_ID) {
+ resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null,
+ preserveWindows);
+ return;
+ }
final ActivityStack stack = getStack(stackId);
if (stack == null) {
Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
return;
}
- if (!allowResizeInDockedMode
- && stackId != DOCKED_STACK_ID && getStack(DOCKED_STACK_ID) != null) {
+ if (!allowResizeInDockedMode && getStack(DOCKED_STACK_ID) != null) {
// If the docked stack exist we don't allow resizes of stacks not caused by the docked
// stack size changing so things don't get out of sync.
return;
@@ -3134,100 +1825,143 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
mWindowManager.deferSurfaceLayout();
try {
-
- if (bounds != null && mWindowManager.isFullscreenBounds(stackId, bounds)) {
- // The bounds passed in corresponds to the fullscreen bounds which we normally
- // represent with null. Go ahead and set it to null so that all tasks configuration
- // can have the right fullscreen state.
- bounds = null;
- }
-
- ActivityRecord r = stack.topRunningActivityLocked();
-
- mTmpBounds.clear();
- mTmpConfigs.clear();
- ArrayList<TaskRecord> tasks = stack.getAllTasks();
- for (int i = tasks.size() - 1; i >= 0; i--) {
- TaskRecord task = tasks.get(i);
- if (task.mResizeable) {
- if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
- // For freeform stack we don't adjust the size of the tasks to match that
- // of the stack, but we do try to make sure the tasks are still contained
- // with the bounds of the stack.
- tempRect2.set(task.mBounds);
- fitWithinBounds(tempRect2, bounds);
- task.updateOverrideConfiguration(tempRect2);
- } else {
- task.updateOverrideConfiguration(bounds);
- }
- }
-
- mTmpConfigs.put(task.taskId, task.mOverrideConfig);
- mTmpBounds.put(task.taskId, task.mBounds);
- }
- stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
- if (stack.mStackId == DOCKED_STACK_ID) {
- // Dock stack funness...Yay!
- if (stack.mFullscreen) {
- // The dock stack went fullscreen which is kinda like dismissing it.
- // In this case we make all other static stacks fullscreen and move all
- // docked stack tasks to the fullscreen stack.
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
- resizeStackLocked(i, null, preserveWindows, true);
- }
- }
-
- final int count = tasks.size();
- for (int i = 0; i < count; i++) {
- moveTaskToStackLocked(tasks.get(i).taskId,
- FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
- false /* animate */);
- }
-
- // stack shouldn't contain anymore activities, so nothing to resume.
- r = null;
- } else {
- // Docked stacks occupy a dedicated region on screen so the size of all other
- // static stacks need to be adjusted so they don't overlap with the docked stack.
- // We get the bounds to use from window manager which has been adjusted for any
- // screen controls and is also the same for all stacks.
- mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
-
- for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
- if (StackId.isResizeableByDockedStack(i)) {
- ActivityStack otherStack = getStack(i);
- if (otherStack != null) {
- resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
- }
- }
- }
- }
- // Since we are resizing the stack, all other operations should strive to preserve
- // windows.
- preserveWindows = true;
- }
- stack.setBounds(bounds);
-
- if (r != null) {
- final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
- // And we need to make sure at this point that all other activities
- // are made visible with the correct configuration.
- ensureActivitiesVisibleLocked(r, 0, preserveWindows);
- if (!updated) {
- resumeTopActivitiesLocked(stack, null, null);
- }
- }
+ resizeStackUncheckedLocked(stack, bounds, tempTaskBounds, tempTaskInsetBounds);
+ ensureConfigurationAndResume(stack, stack.topRunningActivityLocked(), preserveWindows);
} finally {
mWindowManager.continueSurfaceLayout();
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
}
- void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
+ private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+ Rect tempTaskInsetBounds) {
+ if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) {
+ // The bounds passed in corresponds to the fullscreen bounds which we normally
+ // represent with null. Go ahead and set it to null so that all tasks configuration
+ // can have the right fullscreen state.
+ bounds = null;
+ }
+
+ mTmpBounds.clear();
+ mTmpConfigs.clear();
+ mTmpInsetBounds.clear();
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ for (int i = tasks.size() - 1; i >= 0; i--) {
+ TaskRecord task = tasks.get(i);
+ if (task.mResizeable) {
+ if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+ // For freeform stack we don't adjust the size of the tasks to match that
+ // of the stack, but we do try to make sure the tasks are still contained
+ // with the bounds of the stack.
+ tempRect2.set(task.mBounds);
+ fitWithinBounds(tempRect2, bounds);
+ task.updateOverrideConfiguration(tempRect2);
+ } else {
+ task.updateOverrideConfiguration(tempTaskBounds != null
+ ? tempTaskBounds : bounds);
+ }
+ }
+
+ mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpBounds.put(task.taskId, task.mBounds);
+ if (tempTaskInsetBounds != null) {
+ mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+ }
+ }
+
+ // We might trigger a configuration change. Save the current task bounds for freezing.
+ mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+ stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs,
+ mTmpBounds, mTmpInsetBounds);
+ stack.setBounds(bounds);
+ }
+
+ private void ensureConfigurationAndResume(ActivityStack stack, ActivityRecord r,
+ boolean preserveWindows) {
+ if (r == null) {
+ return;
+ }
+ final boolean updated = stack.ensureActivityConfigurationLocked(r, 0,
+ preserveWindows);
+ // And we need to make sure at this point that all other activities
+ // are made visible with the correct configuration.
+ ensureActivitiesVisibleLocked(r, 0, preserveWindows);
+ if (!updated) {
+ resumeFocusedStackTopActivityLocked();
+ }
+ }
+
+ void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+ Rect tempDockedTaskInsetBounds,
+ Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) {
+ final ActivityStack stack = getStack(DOCKED_STACK_ID);
+ if (stack == null) {
+ Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
+ return;
+ }
+
+ Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeDockedStack");
+ mWindowManager.deferSurfaceLayout();
+ try {
+ ActivityRecord r = stack.topRunningActivityLocked();
+ resizeStackUncheckedLocked(stack, dockedBounds, tempDockedTaskBounds,
+ tempDockedTaskInsetBounds);
+
+ if (stack.mFullscreen) {
+ // The dock stack went fullscreen which is kinda like dismissing it.
+ // In this case we make all other static stacks fullscreen and move all
+ // docked stack tasks to the fullscreen stack.
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
+ resizeStackLocked(i, null, null, null, preserveWindows,
+ true /* allowResizeInDockedMode */);
+ }
+ }
+
+ ArrayList<TaskRecord> tasks = stack.getAllTasks();
+ final int count = tasks.size();
+ for (int i = 0; i < count; i++) {
+ moveTaskToStackLocked(tasks.get(i).taskId,
+ FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
+ false /* animate */);
+ }
+
+ // stack shouldn't contain anymore activities, so nothing to resume.
+ r = null;
+ } else {
+ // Docked stacks occupy a dedicated region on screen so the size of all other
+ // static stacks need to be adjusted so they don't overlap with the docked stack.
+ // We get the bounds to use from window manager which has been adjusted for any
+ // screen controls and is also the same for all stacks.
+ mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+ for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+ if (StackId.isResizeableByDockedStack(i)) {
+ ActivityStack otherStack = getStack(i);
+ if (otherStack != null) {
+ resizeStackLocked(i, tempRect, tempOtherTaskBounds,
+ tempOtherTaskInsetBounds, preserveWindows,
+ true /* allowResizeInDockedMode */);
+ }
+ }
+ }
+ }
+ ensureConfigurationAndResume(stack, r, preserveWindows);
+ } finally {
+ mWindowManager.continueSurfaceLayout();
+ Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ }
+
+ mResizeDockedStackTimeout.notifyResizing(dockedBounds,
+ tempDockedTaskBounds != null
+ || tempDockedTaskInsetBounds != null
+ || tempOtherTaskBounds != null
+ || tempOtherTaskInsetBounds != null);
+ }
+
+ boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
if (!task.mResizeable) {
Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
- return;
+ return true;
}
adjustForMinimalTaskDimensions(task, bounds);
@@ -3237,7 +1971,7 @@
final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) {
// Nothing to do here...
- return;
+ return true;
}
if (!mWindowManager.isValidTaskId(task.taskId)) {
@@ -3249,7 +1983,7 @@
// re-restore the task so it can have the proper stack association.
restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
}
- return;
+ return true;
}
// Do not move the task to another stack here.
@@ -3271,13 +2005,14 @@
// All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
- resumeTopActivitiesLocked(stack, null, null);
+ resumeFocusedStackTopActivityLocked();
}
}
}
mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+ return kept;
}
private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) {
@@ -3393,8 +2128,14 @@
ActivityStack moveTaskToStackUncheckedLocked(
TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
final ActivityRecord r = task.getTopActivity();
- final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
- final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+ final ActivityStack prevStack = task.stack;
+ final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
+ final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+ // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+ // Whenever we are moving the top activity from the front stack we want to make sure to move
+ // the stack to the front.
+ final boolean wasFront = isFrontStack(prevStack)
+ && (prevStack.topRunningActivityLocked() == r);
final boolean resizeable = task.mResizeable;
// Temporarily disable resizeablility of task we are moving. We don't want it to be resized
@@ -3407,9 +2148,9 @@
stack.addTask(task, toTop, reason);
// If the task had focus before (or we're requested to move focus),
- // move focus to the new stack.
- stack.setFocusAndResumeStateIfNeeded(
- r, forceFocus || wasFocused, wasResumed, reason);
+ // move focus to the new stack by moving the stack to the front.
+ stack.moveToFrontAndResumeStateIfNeeded(
+ r, forceFocus || wasFocused || wasFront, wasResumed, reason);
return stack;
}
@@ -3429,13 +2170,17 @@
}
final ActivityRecord topActivity = task.getTopActivity();
- if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) {
+ final boolean mightReplaceWindow =
+ StackId.preserveWindowOnTaskMove(stackId) && topActivity != null;
+ if (mightReplaceWindow) {
// We are about to relaunch the activity because its configuration changed due to
// being maximized, i.e. size change. The activity will first remove the old window
// and then add a new one. This call will tell window manager about this, so it can
// preserve the old window until the new one is drawn. This prevents having a gap
// between the removal and addition, in which no window is visible. We also want the
// entrance of the new window to be properly animated.
+ // Note here we always set the replacing window first, as the flags might be needed
+ // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
mWindowManager.setReplacingWindow(topActivity.appToken, animate);
}
final ActivityStack stack = moveTaskToStackUncheckedLocked(
@@ -3445,21 +2190,29 @@
stack.mNoAnimActivities.add(topActivity);
}
+ boolean kept = true;
// Make sure the task has the appropriate bounds/size for the stack it is in.
if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == FREEFORM_WORKSPACE_STACK_ID
&& task.mBounds == null && task.mLastNonFullscreenBounds != null) {
- resizeTaskLocked(task, task.mLastNonFullscreenBounds,
+ kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds,
RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
} else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
- resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
+ }
+
+ if (mightReplaceWindow) {
+ // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
+ // window), we need to clear the replace window settings. Otherwise, we schedule a
+ // timeout to remove the old window if the replacing window is not coming in time.
+ mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept);
}
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
if (!task.mResizeable && isStackDockedInEffect(stackId)) {
showNonResizeableDockToast(taskId);
@@ -3480,31 +2233,42 @@
return false;
}
- if (!r.info.supportsPip) {
+ if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
Slog.w(TAG,
"moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
- + " r=" + r);
+ + " r=" + r);
return false;
}
+ moveActivityToStackLocked(r, PINNED_STACK_ID, "moveTopActivityToPinnedStack", bounds);
+ return true;
+ }
+
+ void moveActivityToStackLocked(ActivityRecord r, int stackId, String reason, Rect bounds) {
final TaskRecord task = r.task;
if (task.mActivities.size() == 1) {
// There is only one activity in the task. So, we can just move the task over to the
- // pinned stack without re-parenting the activity in a different task.
- moveTaskToStackLocked(task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS,
- "moveTopActivityToPinnedStack", true /* animate */);
+ // stack without re-parenting the activity in a different task.
+ moveTaskToStackLocked(
+ task.taskId, stackId, ON_TOP, FORCE_FOCUS, reason, true /* animate */);
} else {
- final ActivityStack pinnedStack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
- pinnedStack.moveActivityToStack(r);
+ final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+ stack.moveActivityToStack(r);
}
- resizeStackLocked(PINNED_STACK_ID, bounds, !PRESERVE_WINDOWS, true);
+ if (bounds != null) {
+ resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+ null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
+ }
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- resumeTopActivitiesLocked();
- return true;
+ resumeFocusedStackTopActivityLocked();
+
+ if (stackId == PINNED_STACK_ID) {
+ mService.notifyActivityPinnedLocked();
+ }
}
void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -3523,10 +2287,12 @@
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
ActivityRecord findTaskLocked(ActivityRecord r) {
+ mTmpFindTaskResult.r = null;
+ mTmpFindTaskResult.matchedByRootAffinity = false;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -3541,14 +2307,18 @@
"Skipping stack: (new task not allowed) " + stack);
continue;
}
- final ActivityRecord ar = stack.findTaskLocked(r);
- if (ar != null) {
- return ar;
+ stack.findTaskLocked(r, mTmpFindTaskResult);
+ // It is possible to have task in multiple stacks with the same root affinity.
+ // If the match we found was based on root affinity we keep on looking to see if
+ // there is a better match in another stack. We eventually return the match based
+ // on root affinity if we don't find a better match.
+ if (mTmpFindTaskResult.r != null && !mTmpFindTaskResult.matchedByRootAffinity) {
+ return mTmpFindTaskResult.r;
}
}
}
- if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
- return null;
+ if (DEBUG_TASKS && mTmpFindTaskResult.r == null) Slog.d(TAG_TASKS, "No task found");
+ return mTmpFindTaskResult.r;
}
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
@@ -3627,7 +2397,7 @@
final ActivityStack stack = stacks.get(stackNdx);
stack.awakeFromSleepingLocked();
if (isFocusedStack(stack)) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
}
@@ -4396,7 +3166,7 @@
}
}
- private void showNonResizeableDockToast(int taskId) {
+ void showNonResizeableDockToast(int taskId) {
mWindowManager.scheduleShowNonResizeableDockToast(taskId);
}
@@ -4422,7 +3192,7 @@
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
"setLockTaskModeLocked: Tasks remaining, can't unlock");
lockedTask.performClearTaskLocked();
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
return;
}
}
@@ -4463,7 +3233,7 @@
if (andResume) {
findTaskToMoveToFrontLocked(task, 0, null, reason);
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
@@ -4531,7 +3301,7 @@
didSomething = true;
}
if (didSomething) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
}
@@ -4539,6 +3309,18 @@
return mLockTaskModeState;
}
+ void activityRelaunchedLocked(IBinder token) {
+ mWindowManager.notifyAppRelaunchingFinished(token);
+ }
+
+ void activityRelaunchingLocked(ActivityRecord r) {
+ mWindowManager.notifyAppRelaunching(r.appToken);
+ }
+
+ void logStackState() {
+ mActivityMetricsLogger.logWindowState();
+ }
+
private final class ActivityStackSupervisorHandler extends Handler {
public ActivityStackSupervisorHandler(Looper looper) {
@@ -4574,7 +3356,7 @@
} break;
case RESUME_TOP_ACTIVITY_MSG: {
synchronized (mService) {
- resumeTopActivitiesLocked();
+ resumeFocusedStackTopActivityLocked();
}
} break;
case SLEEP_TIMEOUT_MSG: {
@@ -4809,7 +3591,7 @@
long origId = Binder.clearCallingIdentity();
try {
mStack.finishAllActivitiesLocked(false);
- removePendingActivityLaunchesLocked(mStack);
+ mService.mActivityStarter.removePendingActivityLaunchesLocked(mStack);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4828,22 +3610,7 @@
@Override
public final int startActivity(Intent intent) {
- mService.enforceNotIsolatedCaller("ActivityContainer.startActivity");
- final int userId = mService.mUserController.handleIncomingUser(Binder.getCallingPid(),
- Binder.getCallingUid(), mCurrentUser, false,
- ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
-
- // TODO: Switch to user app stacks here.
- String mimeType = intent.getType();
- final Uri data = intent.getData();
- if (mimeType == null && data != null && "content".equals(data.getScheme())) {
- mimeType = mService.getProviderMimeType(data, userId);
- }
- checkEmbeddedAllowedInner(userId, intent, mimeType);
-
- intent.addFlags(FORCE_NEW_TASK_FLAGS);
- return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null,
- 0, 0, null, null, null, null, false, userId, this, null);
+ return mService.startActivity(intent, this);
}
@Override
@@ -4867,7 +3634,7 @@
FORCE_NEW_TASK_FLAGS, FORCE_NEW_TASK_FLAGS, null, this);
}
- private void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
+ void checkEmbeddedAllowedInner(int userId, Intent intent, String resolvedType) {
ActivityInfo aInfo = resolveActivity(intent, resolvedType, 0, null, userId);
if (aInfo != null && (aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
throw new SecurityException(
@@ -4970,7 +3737,7 @@
mSurface = surface;
if (surface != null) {
- mStack.resumeTopActivityLocked(null);
+ resumeFocusedStackTopActivityLocked();
} else {
mContainerState = CONTAINER_STATE_NO_SURFACE;
((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
@@ -5024,7 +3791,7 @@
/** All of the stacks on this display. Order matters, topmost stack is in front of all other
* stacks, bottommost behind. Accessed directly by ActivityManager package classes */
- final ArrayList<ActivityStack> mStacks = new ArrayList<ActivityStack>();
+ final ArrayList<ActivityStack> mStacks = new ArrayList<>();
ActivityRecord mVisibleBehindActivity;
@@ -5153,4 +3920,19 @@
}
}
+ ActivityStack findStackBehind(ActivityStack stack) {
+ // TODO(multi-display): We are only looking for stacks on the default display.
+ final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+ if (display == null) {
+ return null;
+ }
+ final ArrayList<ActivityStack> stacks = display.mStacks;
+ for (int i = stacks.size() - 1; i >= 0; i--) {
+ if (stacks.get(i) == stack && i > 0) {
+ return stacks.get(i - 1);
+ }
+ }
+ throw new IllegalStateException("Failed to find a stack behind stack=" + stack
+ + " in=" + stacks);
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
new file mode 100644
index 0000000..f712613
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -0,0 +1,1735 @@
+package com.android.server.am;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
+import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.EXTRA_INTENT;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_TASK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USER_LEAVING;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAVING;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.ANIMATE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
+import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
+import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.am.ActivityStackSupervisor.TAG_TASKS;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.AppGlobals;
+import android.app.IActivityContainer;
+import android.app.IActivityManager;
+import android.app.IApplicationThread;
+import android.app.KeyguardManager;
+import android.app.PendingIntent;
+import android.app.ProfilerInfo;
+import android.content.ComponentName;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.EventLog;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.app.HeavyWeightSwitcherActivity;
+import com.android.internal.app.IVoiceInteractor;
+import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
+import com.android.server.wm.WindowManagerService;
+
+import java.util.ArrayList;
+
+/**
+ * Controller for interpreting how and then launching activities.
+ *
+ * This class collects all the logic for determining how an intent and flags should be turned into
+ * an activity and associated task and stack.
+ */
+class ActivityStarter {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
+ private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+
+ private final ActivityManagerService mService;
+ private final ActivityStackSupervisor mSupervisor;
+ private WindowManagerService mWindowManager;
+
+ final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
+
+ // Share state variable among methods when starting an activity.
+ private ActivityRecord mStartActivity;
+ private Intent mIntent;
+ private int mCallingUid;
+ private ActivityOptions mOptions;
+
+ private boolean mLaunchSingleTop;
+ private boolean mLaunchSingleInstance;
+ private boolean mLaunchSingleTask;
+ private boolean mLaunchTaskBehind;
+ private int mLaunchFlags;
+
+ private Rect mLaunchBounds;
+
+ private ActivityRecord mNotTop;
+ private boolean mDoResume;
+ private int mStartFlags;
+ private ActivityRecord mSourceRecord;
+
+ private TaskRecord mInTask;
+ private boolean mAddingToTask;
+ private TaskRecord mReuseTask;
+
+ private ActivityInfo mNewTaskInfo;
+ private Intent mNewTaskIntent;
+ private ActivityStack mSourceStack;
+ private ActivityStack mTargetStack;
+ // TODO: Is the mMoveHome flag really needed?
+ private boolean mMovedHome;
+ private boolean mMovedToFront;
+ private boolean mNoAnimation;
+ private boolean mKeepCurTransition;
+
+ private IVoiceInteractionSession mVoiceSession;
+ private IVoiceInteractor mVoiceInteractor;
+
+ private void reset() {
+ mStartActivity = null;
+ mIntent = null;
+ mCallingUid = -1;
+ mOptions = null;
+
+ mLaunchSingleTop = false;
+ mLaunchSingleInstance = false;
+ mLaunchSingleTask = false;
+ mLaunchTaskBehind = false;
+ mLaunchFlags = 0;
+
+ mLaunchBounds = null;
+
+ mNotTop = null;
+ mDoResume = false;
+ mStartFlags = 0;
+ mSourceRecord = null;
+
+ mInTask = null;
+ mAddingToTask = false;
+ mReuseTask = null;
+
+ mNewTaskInfo = null;
+ mNewTaskIntent = null;
+ mSourceStack = null;
+
+ mTargetStack = null;
+ mMovedHome = false;
+ mMovedToFront = false;
+ mNoAnimation = false;
+ mKeepCurTransition = false;
+
+ mVoiceSession = null;
+ mVoiceInteractor = null;
+ }
+
+ ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
+ mService = service;
+ mSupervisor = supervisor;
+ }
+
+ final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+ String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
+ String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
+ ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
+ ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
+ TaskRecord inTask) {
+ int err = ActivityManager.START_SUCCESS;
+
+ ProcessRecord callerApp = null;
+ if (caller != null) {
+ callerApp = mService.getRecordForAppLocked(caller);
+ if (callerApp != null) {
+ callingPid = callerApp.pid;
+ callingUid = callerApp.info.uid;
+ } else {
+ Slog.w(TAG, "Unable to find app for caller " + caller
+ + " (pid=" + callingPid + ") when starting: "
+ + intent.toString());
+ err = ActivityManager.START_PERMISSION_DENIED;
+ }
+ }
+
+ final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
+
+ if (err == ActivityManager.START_SUCCESS) {
+ Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ + "} from uid " + callingUid
+ + " on display " + (container == null ? (mSupervisor.mFocusedStack == null ?
+ Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
+ (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+ container.mActivityDisplay.mDisplayId)));
+ }
+
+ ActivityRecord sourceRecord = null;
+ ActivityRecord resultRecord = null;
+ if (resultTo != null) {
+ sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
+ if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+ "Will send result to " + resultTo + " " + sourceRecord);
+ if (sourceRecord != null) {
+ if (requestCode >= 0 && !sourceRecord.finishing) {
+ resultRecord = sourceRecord;
+ }
+ }
+ }
+
+ final int launchFlags = intent.getFlags();
+
+ if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
+ // Transfer the result target from the source activity to the new
+ // one being started, including any failures.
+ if (requestCode >= 0) {
+ ActivityOptions.abort(options);
+ return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
+ }
+ resultRecord = sourceRecord.resultTo;
+ if (resultRecord != null && !resultRecord.isInStackLocked()) {
+ resultRecord = null;
+ }
+ resultWho = sourceRecord.resultWho;
+ requestCode = sourceRecord.requestCode;
+ sourceRecord.resultTo = null;
+ if (resultRecord != null) {
+ resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
+ }
+ if (sourceRecord.launchedFromUid == callingUid) {
+ // The new activity is being launched from the same uid as the previous
+ // activity in the flow, and asking to forward its result back to the
+ // previous. In this case the activity is serving as a trampoline between
+ // the two, so we also want to update its launchedFromPackage to be the
+ // same as the previous activity. Note that this is safe, since we know
+ // these two packages come from the same uid; the caller could just as
+ // well have supplied that same package name itself. This specifially
+ // deals with the case of an intent picker/chooser being launched in the app
+ // flow to redirect to an activity picked by the user, where we want the final
+ // activity to consider it to have been launched by the previous app activity.
+ callingPackage = sourceRecord.launchedFromPackage;
+ }
+ }
+
+ if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
+ // We couldn't find a class that can handle the given Intent.
+ // That's the end of that!
+ err = ActivityManager.START_INTENT_NOT_RESOLVED;
+ }
+
+ if (err == ActivityManager.START_SUCCESS && aInfo == null) {
+ // We couldn't find the specific class specified in the Intent.
+ // Also the end of the line.
+ err = ActivityManager.START_CLASS_NOT_FOUND;
+ }
+
+ if (err == ActivityManager.START_SUCCESS && sourceRecord != null
+ && sourceRecord.task.voiceSession != null) {
+ // If this activity is being launched as part of a voice session, we need
+ // to ensure that it is safe to do so. If the upcoming activity will also
+ // be part of the voice session, we can only launch it if it has explicitly
+ // said it supports the VOICE category, or it is a part of the calling app.
+ if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
+ && sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
+ try {
+ intent.addCategory(Intent.CATEGORY_VOICE);
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(
+ intent.getComponent(), intent, resolvedType)) {
+ Slog.w(TAG,
+ "Activity being started in current voice task does not support voice: "
+ + intent);
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure checking voice capabilities", e);
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+ }
+
+ if (err == ActivityManager.START_SUCCESS && voiceSession != null) {
+ // If the caller is starting a new voice session, just make sure the target
+ // is actually allowing it to run this way.
+ try {
+ if (!AppGlobals.getPackageManager().activitySupportsIntent(intent.getComponent(),
+ intent, resolvedType)) {
+ Slog.w(TAG,
+ "Activity being started in new voice task does not support: "
+ + intent);
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure checking voice capabilities", e);
+ err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
+ }
+ }
+
+ final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
+
+ if (err != START_SUCCESS) {
+ if (resultRecord != null) {
+ resultStack.sendActivityResultLocked(
+ -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
+ }
+ ActivityOptions.abort(options);
+ return err;
+ }
+
+ boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
+ requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
+ resultRecord, resultStack);
+ abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
+ callingPid, resolvedType, aInfo.applicationInfo);
+
+ if (mService.mController != null) {
+ try {
+ // The Intent we give to the watcher has the extra data
+ // stripped off, since it can contain private information.
+ Intent watchIntent = intent.cloneFilter();
+ abort |= !mService.mController.activityStarting(watchIntent,
+ aInfo.applicationInfo.packageName);
+ } catch (RemoteException e) {
+ mService.mController = null;
+ }
+ }
+
+ final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(intent,
+ resolvedType, aInfo, callingPackage, userId);
+ if (interceptingIntent != null) {
+ intent = interceptingIntent;
+ callingPid = realCallingPid;
+ callingUid = realCallingUid;
+ resolvedType = null;
+ // If we are intercepting and there was a task, convert it into an extra for the
+ // ConfirmCredentials intent and unassign it, as otherwise the task will move to
+ // front even if ConfirmCredentials is cancelled.
+ if (inTask != null) {
+ intent.putExtra(EXTRA_TASK_ID, inTask.taskId);
+ inTask = null;
+ }
+
+ final UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id);
+ aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
+ null /*profilerInfo*/);
+ }
+
+ if (abort) {
+ if (resultRecord != null) {
+ resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
+ RESULT_CANCELED, null);
+ }
+ // We pretend to the caller that it was really started, but
+ // they will just get a cancel result.
+ ActivityOptions.abort(options);
+ return START_SUCCESS;
+ }
+
+ // If permissions need a review before any of the app components can run, we
+ // launch the review activity and pass a pending intent to start the activity
+ // we are to launching now after the review is completed.
+ if (Build.PERMISSIONS_REVIEW_REQUIRED && aInfo != null) {
+ if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ aInfo.packageName, userId)) {
+ IIntentSender target = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ callingUid, userId, null, null, 0, new Intent[]{intent},
+ new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_ONE_SHOT, null);
+
+ final int flags = intent.getFlags();
+ Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ newIntent.setFlags(flags
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
+ newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
+ if (resultRecord != null) {
+ newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
+ }
+ intent = newIntent;
+
+ resolvedType = null;
+ callingUid = realCallingUid;
+ callingPid = realCallingPid;
+
+ rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
+ null /*profilerInfo*/);
+
+ if (DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
+ true, false) + "} from uid " + callingUid + " on display "
+ + (container == null ? (mSupervisor.mFocusedStack == null ?
+ Display.DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId) :
+ (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
+ container.mActivityDisplay.mDisplayId)));
+ }
+ }
+ }
+
+ // If we have an ephemeral app, abort the process of launching the resolved intent.
+ // Instead, launch the ephemeral installer. Once the installer is finished, it
+ // starts either the intent we resolved here [on install error] or the ephemeral
+ // app [on install success].
+ if (rInfo != null && rInfo.ephemeralResolveInfo != null) {
+ // Create a pending intent to start the intent resolved here.
+ final IIntentSender failureTarget = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
+ new String[]{ resolvedType },
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE, null);
+
+ // Create a pending intent to start the ephemeral application; force it to be
+ // directed to the ephemeral package.
+ ephemeralIntent.setPackage(rInfo.ephemeralResolveInfo.getPackageName());
+ final IIntentSender ephemeralTarget = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+ Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ ephemeralIntent },
+ new String[]{ resolvedType },
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE, null);
+
+ int flags = intent.getFlags();
+ intent = new Intent();
+ intent.setFlags(flags
+ | Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME,
+ rInfo.ephemeralResolveInfo.getPackageName());
+ intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, new IntentSender(failureTarget));
+ intent.putExtra(Intent.EXTRA_EPHEMERAL_SUCCESS, new IntentSender(ephemeralTarget));
+
+ resolvedType = null;
+ callingUid = realCallingUid;
+ callingPid = realCallingPid;
+
+ rInfo = rInfo.ephemeralInstaller;
+ aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
+ }
+
+ ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
+ intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
+ requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
+ options);
+ if (outActivity != null) {
+ outActivity[0] = r;
+ }
+
+ if (r.appTimeTracker == null && sourceRecord != null) {
+ // If the caller didn't specify an explicit time tracker, we want to continue
+ // tracking under any it has.
+ r.appTimeTracker = sourceRecord.appTimeTracker;
+ }
+
+ final ActivityStack stack = mSupervisor.mFocusedStack;
+ if (voiceSession == null && (stack.mResumedActivity == null
+ || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
+ if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
+ realCallingPid, realCallingUid, "Activity start")) {
+ PendingActivityLaunch pal = new PendingActivityLaunch(r,
+ sourceRecord, startFlags, stack, callerApp);
+ mPendingActivityLaunches.add(pal);
+ ActivityOptions.abort(options);
+ return ActivityManager.START_SWITCHES_CANCELED;
+ }
+ }
+
+ if (mService.mDidAppSwitch) {
+ // This is the second allowed switch since we stopped switches,
+ // so now just generally allow switches. Use case: user presses
+ // home (switches disabled, switch to home, mDidAppSwitch now true);
+ // user taps a home icon (coming from home so allowed, we hit here
+ // and now allow anyone to switch again).
+ mService.mAppSwitchesAllowedTime = 0;
+ } else {
+ mService.mDidAppSwitch = true;
+ }
+
+ doPendingActivityLaunchesLocked(false);
+
+ err = startActivityUnchecked(
+ r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
+
+ if (err < 0) {
+ // If someone asked to have the keyguard dismissed on the next
+ // activity start, but we are not actually doing an activity
+ // switch... just dismiss the keyguard now, because we
+ // probably want to see whatever is behind it.
+ mSupervisor.notifyActivityDrawnForKeyguard();
+ }
+ return err;
+ }
+
+ /**
+ * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
+ *
+ * @return The intercepting intent if needed.
+ */
+ private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
+ ActivityInfo aInfo, String callingPackage, int userId) {
+ if (!mService.mUserController.shouldConfirmCredentials(userId)) {
+ return null;
+ }
+ final IIntentSender target = mService.getIntentSenderLocked(
+ INTENT_SENDER_ACTIVITY, callingPackage,
+ Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
+ new String[]{ resolvedType },
+ FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
+ final int flags = intent.getFlags();
+ final KeyguardManager km = (KeyguardManager) mService.mContext
+ .getSystemService(KEYGUARD_SERVICE);
+ final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
+ if (newIntent == null) {
+ return null;
+ }
+ newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
+ newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
+ return newIntent;
+ }
+
+ void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
+ mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
+ startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
+ null /*resolvedType*/, aInfo, null /*rInfo*/, null /*voiceSession*/,
+ null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
+ 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
+ 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
+ false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
+ null /*container*/, null /*inTask*/);
+ if (mSupervisor.inResumeTopActivity) {
+ // If we are in resume section already, home activity will be initialized, but not
+ // resumed (to avoid recursive resume) and will stay that way until something pokes it
+ // again. We need to schedule another resume.
+ mSupervisor.scheduleResumeTopActivities();
+ }
+ }
+
+ final int startActivityMayWait(IApplicationThread caller, int callingUid,
+ String callingPackage, Intent intent, String resolvedType,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ IBinder resultTo, String resultWho, int requestCode, int startFlags,
+ ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
+ Bundle bOptions, boolean ignoreTargetSecurity, int userId,
+ IActivityContainer iContainer, TaskRecord inTask) {
+ // Refuse possible leaked file descriptors
+ if (intent != null && intent.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+ boolean componentSpecified = intent.getComponent() != null;
+
+ // Save a copy in case ephemeral needs it
+ final Intent ephemeralIntent = new Intent(intent);
+ // Don't modify the client's object!
+ intent = new Intent(intent);
+
+ ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
+ // Collect information about the target of the Intent.
+ ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
+
+ ActivityOptions options = ActivityOptions.fromBundle(bOptions);
+ ActivityStackSupervisor.ActivityContainer container =
+ (ActivityStackSupervisor.ActivityContainer)iContainer;
+ synchronized (mService) {
+ if (container != null && container.mParentActivity != null &&
+ container.mParentActivity.state != RESUMED) {
+ // Cannot start a child activity if the parent is not resumed.
+ return ActivityManager.START_CANCELED;
+ }
+ final int realCallingPid = Binder.getCallingPid();
+ final int realCallingUid = Binder.getCallingUid();
+ int callingPid;
+ if (callingUid >= 0) {
+ callingPid = -1;
+ } else if (caller == null) {
+ callingPid = realCallingPid;
+ callingUid = realCallingUid;
+ } else {
+ callingPid = callingUid = -1;
+ }
+
+ final ActivityStack stack;
+ if (container == null || container.mStack.isOnHomeDisplay()) {
+ stack = mSupervisor.mFocusedStack;
+ } else {
+ stack = container.mStack;
+ }
+ stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Starting activity when config will change = " + stack.mConfigWillChange);
+
+ final long origId = Binder.clearCallingIdentity();
+
+ if (aInfo != null &&
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ // This may be a heavy-weight process! Check to see if we already
+ // have another, different heavy-weight process running.
+ if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
+ final ProcessRecord heavy = mService.mHeavyWeightProcess;
+ if (heavy != null && (heavy.info.uid != aInfo.applicationInfo.uid
+ || !heavy.processName.equals(aInfo.processName))) {
+ int appCallingUid = callingUid;
+ if (caller != null) {
+ ProcessRecord callerApp = mService.getRecordForAppLocked(caller);
+ if (callerApp != null) {
+ appCallingUid = callerApp.info.uid;
+ } else {
+ Slog.w(TAG, "Unable to find app for caller " + caller
+ + " (pid=" + callingPid + ") when starting: "
+ + intent.toString());
+ ActivityOptions.abort(options);
+ return ActivityManager.START_PERMISSION_DENIED;
+ }
+ }
+
+ IIntentSender target = mService.getIntentSenderLocked(
+ ActivityManager.INTENT_SENDER_ACTIVITY, "android",
+ appCallingUid, userId, null, null, 0, new Intent[] { intent },
+ new String[] { resolvedType }, PendingIntent.FLAG_CANCEL_CURRENT
+ | PendingIntent.FLAG_ONE_SHOT, null);
+
+ Intent newIntent = new Intent();
+ if (requestCode >= 0) {
+ // Caller is requesting a result.
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_HAS_RESULT, true);
+ }
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_INTENT,
+ new IntentSender(target));
+ if (heavy.activities.size() > 0) {
+ ActivityRecord hist = heavy.activities.get(0);
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP,
+ hist.packageName);
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK,
+ hist.task.taskId);
+ }
+ newIntent.putExtra(HeavyWeightSwitcherActivity.KEY_NEW_APP,
+ aInfo.packageName);
+ newIntent.setFlags(intent.getFlags());
+ newIntent.setClassName("android",
+ HeavyWeightSwitcherActivity.class.getName());
+ intent = newIntent;
+ resolvedType = null;
+ caller = null;
+ callingUid = Binder.getCallingUid();
+ callingPid = Binder.getCallingPid();
+ componentSpecified = true;
+ rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId);
+ aInfo = rInfo != null ? rInfo.activityInfo : null;
+ if (aInfo != null) {
+ aInfo = mService.getActivityInfoForUser(aInfo, userId);
+ }
+ }
+ }
+ }
+
+ int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
+ aInfo, rInfo, voiceSession, voiceInteractor,
+ resultTo, resultWho, requestCode, callingPid,
+ callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
+ options, ignoreTargetSecurity, componentSpecified, null, container, inTask);
+
+ Binder.restoreCallingIdentity(origId);
+
+ if (stack.mConfigWillChange) {
+ // If the caller also wants to switch to a new configuration,
+ // do so now. This allows a clean switch, as we are waiting
+ // for the current activity to pause (so we will not destroy
+ // it), and have not yet started the next activity.
+ mService.enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
+ "updateConfiguration()");
+ stack.mConfigWillChange = false;
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Updating to new configuration after starting activity.");
+ mService.updateConfigurationLocked(config, null, false);
+ }
+
+ if (outResult != null) {
+ outResult.result = res;
+ if (res == ActivityManager.START_SUCCESS) {
+ mSupervisor.mWaitingActivityLaunched.add(outResult);
+ do {
+ try {
+ mService.wait();
+ } catch (InterruptedException e) {
+ }
+ } while (!outResult.timeout && outResult.who == null);
+ } else if (res == START_TASK_TO_FRONT) {
+ ActivityRecord r = stack.topRunningActivityLocked();
+ if (r.nowVisible && r.state == RESUMED) {
+ outResult.timeout = false;
+ outResult.who = new ComponentName(r.info.packageName, r.info.name);
+ outResult.totalTime = 0;
+ outResult.thisTime = 0;
+ } else {
+ outResult.thisTime = SystemClock.uptimeMillis();
+ mSupervisor.mWaitingActivityVisible.add(outResult);
+ do {
+ try {
+ mService.wait();
+ } catch (InterruptedException e) {
+ }
+ } while (!outResult.timeout && outResult.who == null);
+ }
+ }
+ }
+
+ return res;
+ }
+ }
+
+ final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
+ Intent[] intents, String[] resolvedTypes, IBinder resultTo,
+ Bundle bOptions, int userId) {
+ if (intents == null) {
+ throw new NullPointerException("intents is null");
+ }
+ if (resolvedTypes == null) {
+ throw new NullPointerException("resolvedTypes is null");
+ }
+ if (intents.length != resolvedTypes.length) {
+ throw new IllegalArgumentException("intents are length different than resolvedTypes");
+ }
+
+
+ int callingPid;
+ if (callingUid >= 0) {
+ callingPid = -1;
+ } else if (caller == null) {
+ callingPid = Binder.getCallingPid();
+ callingUid = Binder.getCallingUid();
+ } else {
+ callingPid = callingUid = -1;
+ }
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ActivityRecord[] outActivity = new ActivityRecord[1];
+ for (int i=0; i<intents.length; i++) {
+ Intent intent = intents[i];
+ if (intent == null) {
+ continue;
+ }
+
+ // Refuse possible leaked file descriptors
+ if (intent != null && intent.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+
+ boolean componentSpecified = intent.getComponent() != null;
+
+ // Don't modify the client's object!
+ intent = new Intent(intent);
+
+ // Collect information about the target of the Intent.
+ ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
+ null, userId);
+ // TODO: New, check if this is correct
+ aInfo = mService.getActivityInfoForUser(aInfo, userId);
+
+ if (aInfo != null &&
+ (aInfo.applicationInfo.privateFlags
+ & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
+ throw new IllegalArgumentException(
+ "FLAG_CANT_SAVE_STATE not supported here");
+ }
+
+ ActivityOptions options = ActivityOptions.fromBundle(
+ i == intents.length - 1 ? bOptions : null);
+ int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
+ resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
+ callingPid, callingUid, callingPackage, callingPid, callingUid, 0,
+ options, false, componentSpecified, outActivity, null, null);
+ if (res < 0) {
+ return res;
+ }
+
+ resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ return START_SUCCESS;
+ }
+
+ private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+
+ setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
+ voiceInteractor);
+
+ computeLaunchingTaskFlags();
+
+ computeSourceStack();
+
+ mIntent.setFlags(mLaunchFlags);
+
+ ActivityRecord intentActivity = getReusableIntentActivity();
+
+ if (intentActivity != null) {
+ // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
+ // still needs to be a lock task mode violation since the task gets cleared out and
+ // the device would otherwise leave the locked task.
+ if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
+ (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
+ mSupervisor.showLockTaskToast();
+ Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ if (mStartActivity.task == null) {
+ mStartActivity.task = intentActivity.task;
+ }
+ if (intentActivity.task.intent == null) {
+ // This task was started because of movement of the activity based on affinity...
+ // Now that we are actually launching it, we can assign the base intent.
+ intentActivity.task.setIntent(mStartActivity);
+ }
+
+ intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
+
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do anything
+ // if that is the case, so this is it! And for paranoia, make sure we have
+ // correctly resumed the top activity.
+ resumeTargetStackIfNeeded();
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+
+ setTaskFromIntentActivity(intentActivity);
+
+ if (!mAddingToTask && mReuseTask == null) {
+ // We didn't do anything... but it was needed (a.k.a., client don't use that
+ // intent!) And for paranoia, make sure we have correctly resumed the top activity.
+ resumeTargetStackIfNeeded();
+ return START_TASK_TO_FRONT;
+ }
+ }
+
+ if (mStartActivity.packageName == null) {
+ if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
+ mStartActivity.resultTo.task.stack.sendActivityResultLocked(
+ -1, mStartActivity.resultTo, mStartActivity.resultWho,
+ mStartActivity.requestCode, RESULT_CANCELED, null);
+ }
+ ActivityOptions.abort(mOptions);
+ return START_CLASS_NOT_FOUND;
+ }
+
+ // If the activity being launched is the same as the one currently at the top, then
+ // we need to check if it should only be launched once.
+ final ActivityStack topStack = mSupervisor.mFocusedStack;
+ final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
+ final boolean dontStart = top != null && mStartActivity.resultTo == null
+ && top.realActivity.equals(mStartActivity.realActivity)
+ && top.userId == mStartActivity.userId
+ && top.app != null && top.app.thread != null
+ && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+ || mLaunchSingleTop || mLaunchSingleTask);
+ if (dontStart) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+ // For paranoia, make sure we have correctly resumed the top activity.
+ topStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ ActivityOptions.abort(mOptions);
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do
+ // anything if that is the case, so this is it!
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+ top.deliverNewIntentLocked(
+ mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ return START_DELIVERED_TO_TOP;
+ }
+
+ boolean newTask = false;
+ final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+ ? mSourceRecord.task : null;
+
+ // Should this be considered a new task?
+ if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
+ && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ newTask = true;
+ setTaskFromReuseOrCreateNewTask(taskToAffiliate);
+
+ if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+ if (!mMovedHome
+ && (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+ // Caller wants to appear on home activity, so before starting
+ // their own activity we will bring home to the front.
+ mStartActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ }
+ } else if (mSourceRecord != null) {
+ if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ final int result = setTaskFromSourceRecord();
+ if (result != START_SUCCESS) {
+ return result;
+ }
+ } else if (mInTask != null) {
+ // The caller is asking that the new activity be started in an explicit
+ // task it has provided to us.
+ if (mSupervisor.isLockTaskModeViolation(mInTask)) {
+ Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+ return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+ }
+
+ final int result = setTaskFromInTask();
+ if (result != START_SUCCESS) {
+ return result;
+ }
+ } else {
+ // This not being started from an existing activity, and not part of a new task...
+ // just put it in the top task, though these days this case should never happen.
+ setTaskToCurrentTopOrCreateNewTask();
+ }
+
+ mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
+ mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
+
+ if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
+ mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
+ }
+ if (newTask) {
+ EventLog.writeEvent(
+ EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+ }
+ ActivityStack.logStartActivity(
+ EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+ mTargetStack.mLastPausedActivity = null;
+ mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
+ if (mDoResume) {
+ if (!mLaunchTaskBehind) {
+ // TODO(b/26381750): Remove this code after verification that all the decision
+ // points above moved targetStack to the front which will also set the focus
+ // activity.
+ mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
+ }
+ mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
+ mOptions);
+ } else {
+ mTargetStack.addRecentActivityLocked(mStartActivity);
+ }
+ mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+
+ if (!mStartActivity.task.mResizeable
+ && mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
+ mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
+ }
+
+ return START_SUCCESS;
+ }
+
+ private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+ boolean doResume, int startFlags, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+ reset();
+
+ mStartActivity = r;
+ mIntent = r.intent;
+ mOptions = options;
+ mCallingUid = r.launchedFromUid;
+ mSourceRecord = sourceRecord;
+ mVoiceSession = voiceSession;
+ mVoiceInteractor = voiceInteractor;
+
+ mLaunchBounds = getOverrideBounds(r, options, inTask);
+
+ mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
+ mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
+ mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
+ mLaunchFlags = adjustLaunchFlagsToDocumentMode(
+ r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
+ mLaunchTaskBehind = r.mLaunchTaskBehind
+ && !mLaunchSingleTask && !mLaunchSingleInstance
+ && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
+
+ sendNewTaskResultRequestIfNeeded();
+
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ }
+
+ // If we are actually going to launch in to a new task, there are some cases where
+ // we further want to do multiple task.
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ if (mLaunchTaskBehind
+ || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
+ mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
+ }
+ }
+
+ // We'll invoke onUserLeaving before onPause only if the launching
+ // activity did not explicitly state that this is an automated launch.
+ mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+ if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+ "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
+
+ // If the caller has asked not to resume at this point, we make note
+ // of this in the record so that we can skip it when trying to find
+ // the top running activity.
+ mDoResume = doResume;
+ if (!doResume || !mSupervisor.okToShowLocked(r)) {
+ r.delayedResume = true;
+ mDoResume = false;
+ }
+
+ mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+
+ mInTask = inTask;
+ // In some flows in to this function, we retrieve the task record and hold on to it
+ // without a lock before calling back in to here... so the task at this point may
+ // not actually be in recents. Check for that, and if it isn't in recents just
+ // consider it invalid.
+ if (inTask != null && !inTask.inRecents) {
+ Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
+ mInTask = null;
+ }
+
+ mStartFlags = startFlags;
+ // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
+ // is the same as the one making the call... or, as a special case, if we do not know
+ // the caller then we count the current top activity as the caller.
+ if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ ActivityRecord checkedCaller = sourceRecord;
+ if (checkedCaller == null) {
+ checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
+ mNotTop);
+ }
+ if (!checkedCaller.realActivity.equals(r.realActivity)) {
+ // Caller is not the same as launcher, so always needed.
+ mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
+ }
+ }
+
+ mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
+ }
+
+ private void sendNewTaskResultRequestIfNeeded() {
+ if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
+ && mStartActivity.resultTo.task.stack != null) {
+ // For whatever reason this activity is being launched into a new task...
+ // yet the caller has requested a result back. Well, that is pretty messed up,
+ // so instead immediately send back a cancel and let the new task continue launched
+ // as normal without a dependency on its originator.
+ Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
+ mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
+ mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+ mStartActivity.resultTo = null;
+ }
+ }
+
+ private void computeLaunchingTaskFlags() {
+ // If the caller is not coming from another activity, but has given us an explicit task into
+ // which they would like us to launch the new activity, then let's see about doing that.
+ if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+ final Intent baseIntent = mInTask.getBaseIntent();
+ final ActivityRecord root = mInTask.getRootActivity();
+ if (baseIntent == null) {
+ ActivityOptions.abort(mOptions);
+ throw new IllegalArgumentException("Launching into task without base intent: "
+ + mInTask);
+ }
+
+ // If this task is empty, then we are adding the first activity -- it
+ // determines the root, and must be launching as a NEW_TASK.
+ if (mLaunchSingleInstance || mLaunchSingleTask) {
+ if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
+ ActivityOptions.abort(mOptions);
+ throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+ + mStartActivity + " into different task " + mInTask);
+ }
+ if (root != null) {
+ ActivityOptions.abort(mOptions);
+ throw new IllegalArgumentException("Caller with mInTask " + mInTask
+ + " has root " + root + " but target is singleInstance/Task");
+ }
+ }
+
+ // If task is empty, then adopt the interesting intent launch flags in to the
+ // activity being started.
+ if (root == null) {
+ final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
+ | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+ mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
+ | (baseIntent.getFlags() & flagsOfInterest);
+ mIntent.setFlags(mLaunchFlags);
+ mInTask.setIntent(mStartActivity);
+ mAddingToTask = true;
+
+ // If the task is not empty and the caller is asking to start it as the root of
+ // a new task, then we don't actually want to start this on the task. We will
+ // bring the task to the front, and possibly give it a new intent.
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+ mAddingToTask = false;
+
+ } else {
+ mAddingToTask = true;
+ }
+
+ mReuseTask = mInTask;
+ } else {
+ mInTask = null;
+ // Launch ResolverActivity in the source task, so that it stays in the task bounds
+ // when in freeform workspace.
+ // Also put noDisplay activities in the source task. These by itself can be placed
+ // in any task/stack, however it could launch other activities like ResolverActivity,
+ // and we want those to stay in the original task.
+ if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
+ && mSourceRecord.isFreeform()) {
+ mAddingToTask = true;
+ }
+ }
+
+ if (mInTask == null) {
+ if (mSourceRecord == null) {
+ // This activity is not being started from another... in this
+ // case we -always- start a new task.
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
+ Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
+ "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ }
+ } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
+ // The original activity who is starting us is running as a single
+ // instance... this new activity it is starting must go on its
+ // own task.
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ } else if (mLaunchSingleInstance || mLaunchSingleTask) {
+ // The activity being started is a single instance... it always
+ // gets launched into its own task.
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ }
+ }
+ }
+
+ private void computeSourceStack() {
+ if (mSourceRecord == null) {
+ mSourceStack = null;
+ return;
+ }
+ if (!mSourceRecord.finishing) {
+ mSourceStack = mSourceRecord.task.stack;
+ return;
+ }
+
+ // If the source is finishing, we can't further count it as our source. This is because the
+ // task it is associated with may now be empty and on its way out, so we don't want to
+ // blindly throw it in to that task. Instead we will take the NEW_TASK flow and try to find
+ // a task for it. But save the task information so it can be used when creating the new task.
+ if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
+ Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+ + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+ mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+ mNewTaskInfo = mSourceRecord.info;
+ mNewTaskIntent = mSourceRecord.task.intent;
+ }
+ mSourceRecord = null;
+ mSourceStack = null;
+ }
+
+ /**
+ * Decide whether the new activity should be inserted into an existing task. Returns null
+ * if not or an ActivityRecord with the task into which the new activity should be added.
+ */
+ private ActivityRecord getReusableIntentActivity() {
+ // We may want to try to place the new activity in to an existing task. We always
+ // do this if the target activity is singleTask or singleInstance; we will also do
+ // this if NEW_TASK has been requested, and there is not an additional qualifier telling
+ // us to still place it in a new task: multi task, always doc mode, or being asked to
+ // launch this as a new task behind the current one.
+ boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
+ (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+ || mLaunchSingleInstance || mLaunchSingleTask;
+ // If bring to front is requested, and no result is requested and we have not been given
+ // an explicit task to launch in to, and we can find a task that was started with this
+ // same component, then instead of launching bring that one to the front.
+ putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
+ ActivityRecord intentActivity = null;
+ if (putIntoExistingTask) {
+ // See if there is a task to bring to the front. If this is a SINGLE_INSTANCE
+ // activity, there can be one and only one instance of it in the history, and it is
+ // always in its own unique task, so we do a special search.
+ intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
+ : mSupervisor.findTaskLocked(mStartActivity);
+ }
+ return intentActivity;
+ }
+
+ private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
+ mTargetStack = intentActivity.task.stack;
+ mTargetStack.mLastPausedActivity = null;
+ // If the target task is not in the front, then we need to bring it to the front...
+ // except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
+ // the same behavior as if a new instance was being started, which means not bringing it
+ // to the front if the caller is not itself in the front.
+ final ActivityStack focusStack = mSupervisor.getFocusedStack();
+ ActivityRecord curTop = (focusStack == null)
+ ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+
+ if (curTop != null && (curTop.task != intentActivity.task ||
+ curTop.task != focusStack.topTask())) {
+ mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+ if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
+ mSourceStack.topActivity().task == mSourceRecord.task)) {
+ // We really do want to push this one into the user's face, right now.
+ if (mLaunchTaskBehind && mSourceRecord != null) {
+ intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
+ }
+ mMovedHome = true;
+ final ActivityStack launchStack =
+ getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+ mOptions, true);
+ if (launchStack == null || launchStack == mTargetStack) {
+ // We only want to move to the front, if we aren't going to launch on a
+ // different stack. If we launch on a different stack, we will put the
+ // task on top there.
+ mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
+ mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
+ mMovedToFront = true;
+ }
+ if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+ // Caller wants to appear on home activity.
+ intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ }
+ mOptions = null;
+ }
+ }
+ if (!mMovedToFront && mDoResume) {
+ if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
+ + " from " + intentActivity);
+ mTargetStack.moveToFront("intentActivityFound");
+ }
+
+ // If the caller has requested that the target task be reset, then do so.
+ if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+ return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
+ }
+ return intentActivity;
+ }
+
+ private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
+ if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+ == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
+ // The caller has requested to completely replace any existing task with its new
+ // activity. Well that should not be too hard...
+ mReuseTask = intentActivity.task;
+ mReuseTask.performClearTaskLocked();
+ mReuseTask.setIntent(mStartActivity);
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+ || mLaunchSingleInstance || mLaunchSingleTask) {
+ // In this situation we want to remove all activities from the task up to the one
+ // being started. In most cases this means we are resetting the task to its initial
+ // state.
+ ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+ mLaunchFlags);
+ if (top != null) {
+ if (top.frontOfTask) {
+ // Activity aliases may mean we use different intents for the top activity,
+ // so make sure the task now has the identity of the new intent.
+ top.task.setIntent(mStartActivity);
+ }
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ } else {
+ // A special case: we need to start the activity because it is not currently
+ // running, and the caller has asked to clear the current task to have this
+ // activity at the top.
+ mAddingToTask = true;
+ // Now pretend like this activity is being started by the top of its task, so it
+ // is put in the right place.
+ mSourceRecord = intentActivity;
+ final TaskRecord task = mSourceRecord.task;
+ if (task != null && task.stack == null) {
+ // Target stack got cleared when we all activities were removed above.
+ // Go ahead and reset it.
+ mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
+ null /* bounds */, mLaunchFlags, mOptions);
+ mTargetStack.addTask(task,
+ !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
+ }
+ }
+ } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+ // In this case the top activity on the task is the same as the one being launched,
+ // so we take that as a request to bring the task to the foreground. If the top
+ // activity in the task is the root activity, deliver this new intent to it if it
+ // desires.
+ if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
+ && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity,
+ intentActivity.task);
+ if (intentActivity.frontOfTask) {
+ intentActivity.task.setIntent(mStartActivity);
+ }
+ intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+ mStartActivity.launchedFromPackage);
+ } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+ // In this case we are launching the root activity of the task, but with a
+ // different intent. We should start a new instance on top.
+ mAddingToTask = true;
+ mSourceRecord = intentActivity;
+ }
+ } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+ // In this case an activity is being launched in to an existing task, without
+ // resetting that task. This is typically the situation of launching an activity
+ // from a notification or shortcut. We want to place the new activity on top of the
+ // current task.
+ mAddingToTask = true;
+ mSourceRecord = intentActivity;
+ } else if (!intentActivity.task.rootWasReset) {
+ // In this case we are launching into an existing task that has not yet been started
+ // from its front door. The current task has been brought to the front. Ideally,
+ // we'd probably like to place this new task at the bottom of its stack, but that's
+ // a little hard to do with the current organization of the code so for now we'll
+ // just drop it.
+ intentActivity.task.setIntent(mStartActivity);
+ }
+ }
+
+ private void resumeTargetStackIfNeeded() {
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
+ if (!mMovedToFront) {
+ // Make sure to notify Keyguard as well if we are not running an app transition
+ // later.
+ mSupervisor.notifyActivityDrawnForKeyguard();
+ }
+ } else {
+ ActivityOptions.abort(mOptions);
+ }
+ mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+ }
+
+ private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
+ mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
+ mOptions);
+ if (mDoResume) {
+ mTargetStack.moveToFront("startingNewTask");
+ }
+
+ if (mReuseTask == null) {
+ final TaskRecord task = mTargetStack.createTaskRecord(mSupervisor.getNextTaskId(),
+ mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
+ mNewTaskIntent != null ? mNewTaskIntent : mIntent,
+ mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+ mStartActivity.setTask(task, taskToAffiliate);
+ if (mLaunchBounds != null) {
+ mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
+ }
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " +
+ mStartActivity + " in new task " + mStartActivity.task);
+ } else {
+ mStartActivity.setTask(mReuseTask, taskToAffiliate);
+ }
+ }
+
+ private int setTaskFromSourceRecord() {
+ final TaskRecord sourceTask = mSourceRecord.task;
+ // We only want to allow changing stack if the target task is not the top one,
+ // otherwise we would move the launching task to the other side, rather than show
+ // two side by side.
+ final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
+ mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+
+ if (mTargetStack == null) {
+ mTargetStack = sourceTask.stack;
+ } else if (mTargetStack != sourceTask.stack) {
+ mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
+ ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
+ }
+ if (mDoResume) {
+ mTargetStack.moveToFront("sourceStackToFront");
+ }
+ final TaskRecord topTask = mTargetStack.topTask();
+ if (topTask != sourceTask) {
+ mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
+ mStartActivity.appTimeTracker, "sourceTaskToFront");
+ }
+ if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+ // In this case, we are adding the activity to an existing task, but the caller has
+ // asked to clear that task if the activity is already running.
+ ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
+ mKeepCurTransition = true;
+ if (top != null) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ // For paranoia, make sure we have correctly resumed the top activity.
+ mTargetStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ ActivityOptions.abort(mOptions);
+ return START_DELIVERED_TO_TOP;
+ }
+ } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+ // In this case, we are launching an activity in our own task that may already be
+ // running somewhere in the history, and we want to shuffle it to the front of the
+ // stack if so.
+ final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
+ if (top != null) {
+ final TaskRecord task = top.task;
+ task.moveActivityToFrontLocked(top);
+ top.updateOptionsLocked(mOptions);
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, task);
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ mTargetStack.mLastPausedActivity = null;
+ if (mDoResume) {
+ mSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ return START_DELIVERED_TO_TOP;
+ }
+ }
+
+ // An existing activity is starting this new activity, so we want to keep the new one in
+ // the same task as the one that is starting it.
+ mStartActivity.setTask(sourceTask, null);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+ + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+ return START_SUCCESS;
+ }
+
+ private int setTaskFromInTask() {
+ if (mLaunchBounds != null) {
+ mInTask.updateOverrideConfiguration(mLaunchBounds);
+ int stackId = mInTask.getLaunchStackId();
+ if (stackId != mInTask.stack.mStackId) {
+ mSupervisor.moveTaskToStackUncheckedLocked(
+ mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+ }
+ }
+ mTargetStack = mInTask.stack;
+ mTargetStack.moveTaskToFrontLocked(
+ mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
+
+ // Check whether we should actually launch the new activity in to the task,
+ // or just reuse the current activity on top.
+ ActivityRecord top = mInTask.getTopActivity();
+ if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+ if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+ || mLaunchSingleTop || mLaunchSingleTask) {
+ ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+ if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+ // We don't need to start a new activity, and the client said not to do
+ // anything if that is the case, so this is it!
+ return START_RETURN_INTENT_TO_CALLER;
+ }
+ top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+ return START_DELIVERED_TO_TOP;
+ }
+ }
+
+ if (!mAddingToTask) {
+ // We don't actually want to have this activity added to the task, so just
+ // stop here but still tell the caller that we consumed the intent.
+ ActivityOptions.abort(mOptions);
+ return START_TASK_TO_FRONT;
+ }
+
+ mStartActivity.setTask(mInTask, null);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+
+ return START_SUCCESS;
+ }
+
+ private void setTaskToCurrentTopOrCreateNewTask() {
+ mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
+ mOptions);
+ if (mDoResume) {
+ mTargetStack.moveToFront("addingToTopTask");
+ }
+ final ActivityRecord prev = mTargetStack.topActivity();
+ final TaskRecord task = prev != null ? prev.task
+ : mTargetStack.createTaskRecord(
+ mSupervisor.getNextTaskId(), mStartActivity.info, mIntent, null, null, true);
+ mStartActivity.setTask(task, null);
+ mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+ if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+ "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
+ }
+
+ private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
+ boolean launchSingleTask, int launchFlags) {
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
+ (launchSingleInstance || launchSingleTask)) {
+ // We have a conflict between the Intent and the Activity manifest, manifest wins.
+ Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
+ "\"singleInstance\" or \"singleTask\"");
+ launchFlags &=
+ ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
+ } else {
+ switch (r.info.documentLaunchMode) {
+ case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+ launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+ launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+ break;
+ case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
+ launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
+ break;
+ }
+ }
+ return launchFlags;
+ }
+
+ final void doPendingActivityLaunchesLocked(boolean doResume) {
+ while (!mPendingActivityLaunches.isEmpty()) {
+ PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
+
+ try {
+ startActivityUnchecked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ doResume && mPendingActivityLaunches.isEmpty(), null, null);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
+ pal.sendErrorResult(e.getMessage());
+ }
+ }
+ }
+
+ private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
+ int launchFlags, ActivityOptions aOptions) {
+ final TaskRecord task = r.task;
+ if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+ return mSupervisor.mHomeStack;
+ }
+
+ ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
+ if (stack != null) {
+ return stack;
+ }
+
+ if (task != null && task.stack != null) {
+ stack = task.stack;
+ if (stack.isOnHomeDisplay()) {
+ if (mSupervisor.mFocusedStack != stack) {
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+ "computeStackFocus: Setting " + "focused stack to r=" + r
+ + " task=" + task);
+ } else {
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+ "computeStackFocus: Focused stack already="
+ + mSupervisor.mFocusedStack);
+ }
+ }
+ return stack;
+ }
+
+ final ActivityStackSupervisor.ActivityContainer container = r.mInitialActivityContainer;
+ if (container != null) {
+ // The first time put it on the desired stack, after this put on task stack.
+ r.mInitialActivityContainer = null;
+ return container.mStack;
+ }
+
+ // The fullscreen stack can contain any task regardless of if the task is resizeable
+ // or not. So, we let the task go in the fullscreen task if it is the focus stack.
+ // If the freeform or docked stack has focus, and the activity to be launched is resizeable,
+ // we can also put it in the focused stack.
+ final int focusedStackId = mSupervisor.mFocusedStack.mStackId;
+ final boolean canUseFocusedStack =
+ focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
+ || focusedStackId == DOCKED_STACK_ID
+ || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeable());
+ if (canUseFocusedStack && (!newTask
+ || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+ "computeStackFocus: Have a focused stack=" + mSupervisor.mFocusedStack);
+ return mSupervisor.mFocusedStack;
+ }
+
+ // We first try to put the task in the first dynamic stack.
+ final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
+ for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ stack = homeDisplayStacks.get(stackNdx);
+ if (!ActivityManager.StackId.isStaticStack(stack.mStackId)) {
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+ "computeStackFocus: Setting focused stack=" + stack);
+ return stack;
+ }
+ }
+
+ // If there is no suitable dynamic stack then we figure out which static stack to use.
+ final int stackId = task != null ? task.getLaunchStackId() :
+ bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
+ FULLSCREEN_WORKSPACE_STACK_ID;
+ stack = mSupervisor.getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+ if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+ + r + " stackId=" + stack.mStackId);
+ return stack;
+ }
+
+ private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+ ActivityOptions aOptions, boolean launchToSideAllowed) {
+ final int launchStackId =
+ (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+ if (isValidLaunchStackId(launchStackId, r)) {
+ return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
+ }
+
+ if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
+ return null;
+ }
+
+ // The parent activity doesn't want to launch the activity on top of itself, but
+ // instead tries to put it onto other side in side-by-side mode.
+ final ActivityStack parentStack = task != null ? task.stack
+ : r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
+ : mSupervisor.mFocusedStack;
+ if (parentStack != null && parentStack.mStackId == DOCKED_STACK_ID) {
+ // If parent was in docked stack, the natural place to launch another activity
+ // will be fullscreen, so it can appear alongside the docked window.
+ return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+ } else {
+ // If the parent is not in the docked stack, we check if there is docked window
+ // and if yes, we will launch into that stack. If not, we just put the new
+ // activity into parent's stack, because we can't find a better place.
+ final ActivityStack stack = mSupervisor.getStack(DOCKED_STACK_ID);
+ if (stack != null && !stack.isStackVisibleLocked()) {
+ // There is a docked stack, but it isn't visible, so we can't launch into that.
+ return null;
+ } else {
+ return stack;
+ }
+ }
+ }
+
+ private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+ if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
+ || !StackId.isStaticStack(stackId)) {
+ return false;
+ }
+
+ final boolean resizeable = r.isResizeable() || mService.mForceResizableActivities;
+
+ if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !resizeable) {
+ return false;
+ }
+
+ if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+ return false;
+ }
+
+ final boolean supportsPip = mService.mSupportsPictureInPicture
+ && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
+ if (stackId == PINNED_STACK_ID && !supportsPip) {
+ return false;
+ }
+ return true;
+ }
+
+ Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+ Rect newBounds = null;
+ if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(
+ options, options.getLaunchStackId())) {
+ newBounds = options.getLaunchBounds();
+ }
+ }
+ return newBounds;
+ }
+
+ void setWindowManager(WindowManagerService wm) {
+ mWindowManager = wm;
+ }
+
+ void removePendingActivityLaunchesLocked(ActivityStack stack) {
+ for (int palNdx = mPendingActivityLaunches.size() - 1; palNdx >= 0; --palNdx) {
+ PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx);
+ if (pal.stack == stack) {
+ mPendingActivityLaunches.remove(palNdx);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index f64b803..82862e8 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1114,7 +1114,7 @@
} else {
// Not an option, last argument must be a package name.
try {
- reqUid = mContext.getPackageManager().getPackageUid(arg,
+ reqUid = mContext.getPackageManager().getPackageUidAsUser(arg,
UserHandle.getCallingUserId());
} catch (PackageManager.NameNotFoundException e) {
pw.println("Unknown package: " + arg);
diff --git a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
new file mode 100644
index 0000000..ff39589
--- /dev/null
+++ b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import android.graphics.Rect;
+import android.os.Handler;
+
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+/**
+ * When resizing the docked stack, a caller can temporarily supply task bounds that are different
+ * from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
+ * this class manages this cycle.
+ */
+class ResizeDockedStackTimeout {
+
+ private static final long TIMEOUT_MS = 10 * 1000;
+ private final ActivityManagerService mService;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Handler mHandler;
+ private final Rect mCurrentDockedBounds = new Rect();
+
+ private final Runnable mTimeoutRunnable = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mService) {
+ mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
+ PRESERVE_WINDOWS);
+ }
+ }
+ };
+
+ ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
+ Handler handler) {
+ mService = service;
+ mSupervisor = supervisor;
+ mHandler = handler;
+ }
+
+ void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
+ mHandler.removeCallbacks(mTimeoutRunnable);
+ if (!hasTempBounds) {
+ return;
+ }
+ mCurrentDockedBounds.set(dockedBounds);
+ mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
+ }
+
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 5ee9eea..c97d09c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -441,7 +442,7 @@
} else {
autoRemoveRecents = false;
}
- mResizeable = info.resizeable || mService.mForceResizableActivities;
+ mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities;
mLockTaskMode = info.lockTaskLaunchMode;
mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
setLockTaskAuth();
@@ -697,7 +698,7 @@
if (mActivities.isEmpty()) {
taskType = r.mActivityType;
if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
- mResizeable = r.info.resizeable;
+ mResizeable = r.isResizeable();
}
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
@@ -1321,7 +1322,12 @@
}
}
- void reportPictureInPictureModeChange() {
+ void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) {
+ if (prevStack == null || prevStack == stack
+ || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
+ return;
+ }
+
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mActivities.get(i);
if (r.app != null && r.app.thread != null) {
@@ -1394,6 +1400,12 @@
return mLastNonFullscreenBounds;
}
+ boolean canMatchRootAffinity() {
+ // We don't allow root affinity matching on the pinned stack as no other task should
+ // be launching in it based on affinity.
+ return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("userId="); pw.print(userId);
pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 62e78a4..7172859 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -22,6 +22,7 @@
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.content.Context.KEYGUARD_SERVICE;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -43,6 +44,7 @@
import android.app.Dialog;
import android.app.IStopUserCallback;
import android.app.IUserSwitchObserver;
+import android.app.KeyguardManager;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
@@ -73,6 +75,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.LockPatternUtils;
import com.android.server.pm.UserManagerService;
import java.io.PrintWriter;
@@ -215,7 +218,8 @@
Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+ intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null,
new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
@@ -245,6 +249,7 @@
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0));
final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
+ unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
unlockedIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null,
@@ -302,7 +307,10 @@
+ relatedUserId);
// We still need to stop the requested user if it's a force stop.
if (force) {
+ Slog.i(TAG,
+ "Force stop user " + userId + ". Related users will not be stopped");
stopSingleUserLocked(userId, callback);
+ return USER_OP_SUCCESS;
}
return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
}
@@ -430,6 +438,10 @@
synchronized (mService) {
mService.mStackSupervisor.removeUserLocked(userId);
}
+ // Remove the user if it is ephemeral.
+ if (getUserInfo(userId).isEphemeral()) {
+ mUserManager.removeUser(userId);
+ }
}
}
@@ -476,9 +488,9 @@
}
/**
- * Stops the guest user if it has gone to the background.
+ * Stops the guest or ephemeral user if it has gone to the background.
*/
- private void stopGuestUserIfBackground() {
+ private void stopGuestOrEphemeralUserIfBackground() {
synchronized (mService) {
final int num = mUserLru.size();
for (int i = 0; i < num; i++) {
@@ -490,7 +502,7 @@
continue;
}
UserInfo userInfo = getUserInfo(oldUserId);
- if (userInfo.isGuest()) {
+ if (userInfo.isGuest() || userInfo.isEphemeral()) {
// This is a user to be stopped.
stopUsersLocked(oldUserId, true, null);
break;
@@ -916,7 +928,7 @@
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
newUserId, 0));
}
- stopGuestUserIfBackground();
+ stopGuestOrEphemeralUserIfBackground();
stopBackgroundUsersIfEnforced(oldUserId);
}
@@ -925,7 +937,7 @@
if (homeInFront) {
mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
} else {
- mService.mStackSupervisor.resumeTopActivitiesLocked();
+ mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
}
EventLogTags.writeAmSwitchUser(newUserId);
getUserManager().onUserForeground(newUserId);
@@ -1220,7 +1232,7 @@
}
private boolean isCurrentUserLocked(int userId) {
- return mCurrentUserId == userId || mTargetUserId == userId;
+ return userId == getCurrentOrTargetUserIdLocked();
}
int setTargetUserIdLocked(int targetUserId) {
@@ -1277,6 +1289,20 @@
return mCurrentProfileIds;
}
+ /**
+ * Returns whether the given user requires credential entry at this time. This is used to
+ * intercept activity launches for work apps when the Work Challenge is present.
+ */
+ boolean shouldConfirmCredentials(int userId) {
+ final UserInfo user = getUserInfo(userId);
+ if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+ return false;
+ }
+ final KeyguardManager km = (KeyguardManager) mService.mContext
+ .getSystemService(KEYGUARD_SERVICE);
+ return km.isDeviceLocked(user.id);
+ }
+
void dump(PrintWriter pw, boolean dumpAll) {
pw.println(" mStartedUsers:");
for (int i = 0; i < mStartedUsers.size(); i++) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2bea278..5bd4f98 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -309,7 +309,7 @@
PackageManager pm = mContext.getPackageManager();
int result;
try {
- result = pm.getPackageUid(app, userHandle);
+ result = pm.getPackageUidAsUser(app, userHandle);
} catch (NameNotFoundException e) {
result = -1;
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 8b37383..ee8aab6 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -214,6 +214,7 @@
private static native void nativeSetPointerIconShape(long ptr, int iconId);
private static native void nativeReloadPointerIcons(long ptr);
private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
+ private static native void nativeSetPointerIconDetached(long ptr, boolean detached);
// Input event injection constants defined in InputDispatcher.h.
private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
@@ -320,12 +321,13 @@
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
- nativeReloadPointerIcons(mPtr);
+ updateAccessibilityLargePointerFromSettings();
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
+ updateAccessibilityLargePointerFromSettings();
}
// TODO(BT) Pass in paramter for bluetooth system
@@ -976,7 +978,7 @@
final PackageManager pm = mContext.getPackageManager();
Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
- PackageManager.GET_META_DATA)) {
+ PackageManager.GET_META_DATA | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE)) {
final ActivityInfo activityInfo = resolveInfo.activityInfo;
final int priority = resolveInfo.priority;
visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
@@ -991,7 +993,8 @@
try {
ActivityInfo receiver = pm.getReceiverInfo(
new ComponentName(d.packageName, d.receiverName),
- PackageManager.GET_META_DATA);
+ PackageManager.GET_META_DATA
+ | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
} catch (NameNotFoundException ex) {
}
@@ -1273,6 +1276,11 @@
nativeSetFocusedApplication(mPtr, application);
}
+ @Override
+ public void setPointerIconDetached(boolean detached) {
+ nativeSetPointerIconDetached(mPtr, detached);
+ }
+
public void setInputDispatchMode(boolean enabled, boolean frozen) {
nativeSetInputDispatchMode(mPtr, enabled, frozen);
}
@@ -1366,13 +1374,21 @@
}, UserHandle.USER_ALL);
}
+ public void updateAccessibilityLargePointerFromSettings() {
+ final int accessibilityConfig = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
+ 0, UserHandle.USER_CURRENT);
+ PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
+ nativeReloadPointerIcons(mPtr);
+ }
+
private void registerAccessibilityLargePointerSettingObserver() {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON), true,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
- nativeReloadPointerIcons(mPtr);
+ updateAccessibilityLargePointerFromSettings();
}
}, UserHandle.USER_ALL);
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 309bec8..4eabe36 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -16,20 +16,14 @@
package com.android.server.job;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IUidObserver;
+import android.app.job.IJobScheduler;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.app.job.JobService;
-import android.app.job.IJobScheduler;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -53,6 +47,7 @@
import android.util.SparseArray;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.util.ArrayUtils;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.job.controllers.AppIdleController;
@@ -63,6 +58,15 @@
import com.android.server.job.controllers.StateController;
import com.android.server.job.controllers.TimeController;
+import libcore.util.EmptyArray;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
/**
* Responsible for taking jobs representing work to be performed by a client app, and determining
* based on the criteria specified when that job should be run against the client application's
@@ -126,7 +130,7 @@
*/
final ArrayList<JobStatus> mPendingJobs = new ArrayList<>();
- final ArrayList<Integer> mStartedUsers = new ArrayList<>();
+ int[] mStartedUsers = EmptyArray.INT;
final JobHandler mHandler;
final JobSchedulerStub mJobSchedulerStub;
@@ -157,8 +161,9 @@
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- Slog.d(TAG, "Receieved: " + intent.getAction());
- if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ final String action = intent.getAction();
+ Slog.d(TAG, "Receieved: " + action);
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
// If this is an outright uninstall rather than the first half of an
// app update sequence, cancel the jobs associated with the app.
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
@@ -168,18 +173,21 @@
}
cancelJobsForUid(uidRemoved, true);
}
- } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (DEBUG) {
Slog.d(TAG, "Removing jobs for user: " + userId);
}
cancelJobsForUser(userId);
- } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
- || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+ } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
+ || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
updateIdleMode(mPowerManager != null
? (mPowerManager.isDeviceIdleMode()
|| mPowerManager.isLightDeviceIdleMode())
: false);
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ // Kick off pending jobs for any apps that re-appeared
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
}
};
@@ -201,14 +209,20 @@
@Override
public void onStartUser(int userHandle) {
- mStartedUsers.add(userHandle);
+ mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
+ // Let's kick any outstanding jobs for this user.
+ mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
+ }
+
+ @Override
+ public void onUnlockUser(int userHandle) {
// Let's kick any outstanding jobs for this user.
mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
}
@Override
public void onStopUser(int userHandle) {
- mStartedUsers.remove(Integer.valueOf(userHandle));
+ mStartedUsers = ArrayUtils.removeInt(mStartedUsers, userHandle);
}
/**
@@ -415,17 +429,24 @@
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
- // Register br for package removals and user removals.
+ // Register for package removals and user removals.
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
getContext().registerReceiverAsUser(
mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
- mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
+
+ final IntentFilter storageFilter = new IntentFilter();
+ storageFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ getContext().registerReceiverAsUser(
+ mBroadcastReceiver, UserHandle.ALL, storageFilter, null, null);
+
+ mPowerManager = getContext().getSystemService(PowerManager.class);
try {
ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
ActivityManager.UID_OBSERVER_IDLE);
@@ -744,7 +765,7 @@
*/
private void maybeQueueReadyJobsForExecutionLockedH() {
int chargingCount = 0;
- int idleCount = 0;
+ int idleCount = 0;
int backoffCount = 0;
int connectivityCount = 0;
List<JobStatus> runnableJobs = null;
@@ -812,18 +833,31 @@
* - It's not pending.
* - It's not already running on a JSC.
* - The user that requested the job is running.
+ * - The component is enabled and runnable.
*/
private boolean isReadyToBeExecutedLocked(JobStatus job) {
final boolean jobReady = job.isReady();
final boolean jobPending = mPendingJobs.contains(job);
final boolean jobActive = isCurrentlyActiveLocked(job);
- final boolean userRunning = mStartedUsers.contains(job.getUserId());
+
+ final int userId = job.getUserId();
+ final boolean userStarted = ArrayUtils.contains(mStartedUsers, userId);
+ final boolean componentPresent;
+ try {
+ componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+ job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ userId) != null);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+
if (DEBUG) {
Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
+ " ready=" + jobReady + " pending=" + jobPending
- + " active=" + jobActive + " userRunning=" + userRunning);
+ + " active=" + jobActive + " userStarted=" + userStarted
+ + " componentPresent=" + componentPresent);
}
- return userRunning && jobReady && !jobPending && !jobActive;
+ return userStarted && componentPresent && jobReady && !jobPending && !jobActive;
}
/**
@@ -901,7 +935,8 @@
final IPackageManager pm = AppGlobals.getPackageManager();
final ComponentName service = job.getService();
try {
- ServiceInfo si = pm.getServiceInfo(service, 0, UserHandle.getUserId(uid));
+ ServiceInfo si = pm.getServiceInfo(service,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
if (si == null) {
throw new IllegalArgumentException("No such service " + service);
}
@@ -1014,16 +1049,12 @@
Binder.restoreCallingIdentity(identityToken);
}
}
- };
+ }
void dumpInternal(PrintWriter pw) {
final long now = SystemClock.elapsedRealtime();
synchronized (mJobs) {
- pw.print("Started users: ");
- for (int i=0; i<mStartedUsers.size(); i++) {
- pw.print("u" + mStartedUsers.get(i) + " ");
- }
- pw.println();
+ pw.println("Started users: " + Arrays.toString(mStartedUsers));
pw.println("Registered jobs:");
if (mJobs.size() > 0) {
ArraySet<JobStatus> jobs = mJobs.getJobs();
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index d9f94d0..472e8f6 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -46,6 +46,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -348,9 +349,27 @@
private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
throws IOException, XmlPullParserException {
out.startTag(null, XML_TAG_EXTRAS);
- extras.saveToXml(out);
+ PersistableBundle extrasCopy = deepCopyBundle(extras, 10);
+ extrasCopy.saveToXml(out);
out.endTag(null, XML_TAG_EXTRAS);
}
+
+ private PersistableBundle deepCopyBundle(PersistableBundle bundle, int maxDepth) {
+ if (maxDepth <= 0) {
+ return null;
+ }
+ PersistableBundle copy = (PersistableBundle) bundle.clone();
+ Set<String> keySet = bundle.keySet();
+ for (String key: keySet) {
+ PersistableBundle b = copy.getPersistableBundle(key);
+ if (b != null) {
+ PersistableBundle bCopy = deepCopyBundle(b, maxDepth-1);
+ copy.putPersistableBundle(key, bCopy);
+ }
+ }
+ return copy;
+ }
+
/**
* Write out a tag with data identifying this job's constraints. If the constraint isn't here
* it doesn't apply.
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index d5c3113..745f476 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -767,7 +767,7 @@
synchronized (mLock) {
// If we don't have a media button receiver to fall back on
// include non-playing sessions for dispatching
- UserRecord ur = mUserRecords.get(ActivityManager.getCurrentUser());
+ UserRecord ur = mUserRecords.get(mCurrentUserId);
boolean useNotPlayingSessions = (ur == null) ||
(ur.mLastMediaButtonReceiver == null
&& ur.mRestoredMediaButtonReceiver == null);
@@ -949,8 +949,7 @@
mKeyEventReceiver);
} else {
// Launch the last PendingIntent we had with priority
- int userId = ActivityManager.getCurrentUser();
- UserRecord user = mUserRecords.get(userId);
+ UserRecord user = mUserRecords.get(mCurrentUserId);
if (user != null && (user.mLastMediaButtonReceiver != null
|| user.mRestoredMediaButtonReceiver != null)) {
if (DEBUG) {
@@ -967,11 +966,11 @@
if (user.mLastMediaButtonReceiver != null) {
user.mLastMediaButtonReceiver.send(getContext(),
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
- mediaButtonIntent, mKeyEventReceiver, null);
+ mediaButtonIntent, mKeyEventReceiver, mHandler);
} else {
mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
getContext().sendBroadcastAsUser(mediaButtonIntent,
- new UserHandle(userId));
+ new UserHandle(mCurrentUserId));
}
} catch (CanceledException e) {
Log.i(TAG, "Error sending key event to media button receiver "
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2ac0ba6..5aaa930 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2187,7 +2187,8 @@
// update rules for all installed applications
final List<UserInfo> users = mUserManager.getUsers();
final List<ApplicationInfo> apps = pm.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
+ PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS
+ | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
for (UserInfo user : users) {
for (ApplicationInfo app : apps) {
@@ -2332,7 +2333,7 @@
@Override
public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, userId);
synchronized (mRulesLock) {
updateRuleForAppIdleLocked(uid);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java
new file mode 100644
index 0000000..53ba718
--- /dev/null
+++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.net;
+
+import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
+import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.TrafficStats.UID_TETHERING;
+
+import android.Manifest;
+import android.annotation.IntDef;
+import android.app.AppOpsManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
+
+import com.android.server.LocalServices;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Utility methods for controlling access to network stats APIs. */
+public final class NetworkStatsAccess {
+ private NetworkStatsAccess() {}
+
+ /**
+ * Represents an access level for the network usage history and statistics APIs.
+ *
+ * <p>Access levels are in increasing order; that is, it is reasonable to check access by
+ * verifying that the caller's access level is at least the minimum required level.
+ */
+ @IntDef({
+ Level.DEFAULT,
+ Level.USER,
+ Level.DEVICE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Level {
+ /**
+ * Default, unprivileged access level.
+ *
+ * <p>Can only access usage for one's own UID.
+ *
+ * <p>Every app will have at least this access level.
+ */
+ int DEFAULT = 0;
+
+ /**
+ * Access level for apps which can access usage for any app running in the same user.
+ *
+ * <p>Granted to:
+ * <ul>
+ * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit
+ * so it is not necessarily sufficient to declare this in the manifest.
+ * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission.
+ * <li>Profile owners.
+ * </ul>
+ */
+ int USER = 1;
+
+ /**
+ * Access level for apps which can access usage for any app on the device, including apps
+ * running on other users/profiles.
+ *
+ * <p>Granted to:
+ * <ul>
+ * <li>Device owners.
+ * <li>Carrier-privileged applications.
+ * <li>The system UID.
+ * </ul>
+ */
+ int DEVICE = 2;
+ }
+
+ /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */
+ public static @NetworkStatsAccess.Level int checkAccessLevel(
+ Context context, int callingUid, String callingPackage) {
+ final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+ DevicePolicyManagerInternal.class);
+ final TelephonyManager tm = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ boolean hasCarrierPrivileges = tm != null &&
+ tm.checkCarrierPrivilegesForPackage(callingPackage) ==
+ TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+ boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ if (hasCarrierPrivileges || isDeviceOwner
+ || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) {
+ // Carrier-privileged apps and device owners, and the system can access data usage for
+ // all apps on the device.
+ return NetworkStatsAccess.Level.DEVICE;
+ }
+
+ boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner
+ || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) ==
+ PackageManager.PERMISSION_GRANTED) {
+ // Apps with the AppOps permission, profile owners, and apps with the privileged
+ // permission can access data usage for all apps in this user/profile.
+ return NetworkStatsAccess.Level.USER;
+ }
+
+ // Everyone else gets default access (only to their own UID).
+ return NetworkStatsAccess.Level.DEFAULT;
+ }
+
+ /**
+ * Returns whether the given caller should be able to access the given UID when the caller has
+ * the given {@link NetworkStatsAccess.Level}.
+ */
+ public static boolean isAccessibleToUser(int uid, int callerUid,
+ @NetworkStatsAccess.Level int accessLevel) {
+ switch (accessLevel) {
+ case NetworkStatsAccess.Level.DEVICE:
+ // Device-level access - can access usage for any uid.
+ return true;
+ case NetworkStatsAccess.Level.USER:
+ // User-level access - can access usage for any app running in the same user, along
+ // with some special uids (system, removed, or tethering).
+ return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED
+ || uid == UID_TETHERING
+ || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
+ case NetworkStatsAccess.Level.DEFAULT:
+ default:
+ // Default access level - can only access one's own usage.
+ return uid == callerUid;
+ }
+ }
+
+ private static boolean hasAppOpsPermission(
+ Context context, int callingUid, String callingPackage) {
+ if (callingPackage != null) {
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(
+ Context.APP_OPS_SERVICE);
+
+ final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
+ callingUid, callingPackage);
+ if (mode == AppOpsManager.MODE_DEFAULT) {
+ // The default behavior here is to check if PackageManager has given the app
+ // permission.
+ final int permissionCheck = context.checkCallingPermission(
+ Manifest.permission.PACKAGE_USAGE_STATS);
+ return permissionCheck == PackageManager.PERMISSION_GRANTED;
+ }
+ return (mode == AppOpsManager.MODE_ALLOWED);
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 15b68c7..102695e 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -22,24 +22,18 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
-import static android.net.TrafficStats.UID_TETHERING;
-import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import android.net.ConnectivityManager;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
import android.os.Binder;
-import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IntArray;
-import libcore.io.IoUtils;
-
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
@@ -47,6 +41,8 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import libcore.io.IoUtils;
+
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -136,12 +132,12 @@
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
}
- public int[] getRelevantUids() {
+ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
final int callerUid = Binder.getCallingUid();
IntArray uids = new IntArray();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (isAccessibleToUser(key.uid, callerUid)) {
+ if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) {
int j = uids.binarySearch(key.uid);
if (j < 0) {
@@ -158,8 +154,10 @@
* the requested parameters.
*/
public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields) {
- return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE);
+ NetworkTemplate template, int uid, int set, int tag, int fields,
+ @NetworkStatsAccess.Level int accessLevel) {
+ return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE,
+ accessLevel);
}
/**
@@ -167,9 +165,10 @@
* the requested parameters.
*/
public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) {
+ NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
final int callerUid = Binder.getCallingUid();
- if (!isAccessibleToUser(uid, callerUid)) {
+ if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
throw new SecurityException("Network stats history of uid " + uid
+ " is forbidden for caller " + callerUid);
}
@@ -195,7 +194,8 @@
* Summarize all {@link NetworkStatsHistory} in this collection which match
* the requested parameters.
*/
- public NetworkStats getSummary(NetworkTemplate template, long start, long end) {
+ public NetworkStats getSummary(NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
@@ -208,7 +208,8 @@
final int callerUid = Binder.getCallingUid();
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
- if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)
+ if (templateMatches(template, key.ident)
+ && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)
&& key.set < NetworkStats.SET_DEBUG_START) {
final NetworkStatsHistory value = mStats.valueAt(i);
historyEntry = value.getValues(start, end, now, historyEntry);
@@ -570,12 +571,6 @@
}
}
- private static boolean isAccessibleToUser(int uid, int callerUid) {
- return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID ||
- uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
- || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
- }
-
/**
* Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity}
* in the given {@link NetworkIdentitySet}.
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 6490865..c091960 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -116,7 +116,8 @@
}
public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
- return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+ return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
+ NetworkStatsAccess.Level.DEVICE).getTotal(null);
}
/**
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 8449348..b1d6f89 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -62,13 +62,9 @@
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
-import android.Manifest;
import android.app.AlarmManager;
-import android.app.AppOpsManager;
import android.app.IAlarmManager;
import android.app.PendingIntent;
-import android.app.admin.DeviceAdminInfo;
-import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -97,9 +93,7 @@
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.PowerManager;
-import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -122,7 +116,6 @@
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
-import com.android.server.LocalServices;
import com.android.server.connectivity.Tethering;
import java.io.File;
@@ -484,18 +477,22 @@
@Override
public int[] getRelevantUids() {
- enforcePermissionForManagedAdmin(mCallingPackage);
- return getUidComplete().getRelevantUids();
+ return getUidComplete().getRelevantUids(checkAccessLevel(mCallingPackage));
}
@Override
public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
long end) {
- enforcePermission(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ if (accessLevel < NetworkStatsAccess.Level.DEVICE) {
+ throw new SecurityException("Calling package " + mCallingPackage
+ + " cannot access device-level network stats");
+ }
NetworkStats result = new NetworkStats(end - start, 1);
final long ident = Binder.clearCallingIdentity();
try {
- result.combineAllValues(internalGetSummaryForNetwork(template, start, end));
+ result.combineAllValues(
+ internalGetSummaryForNetwork(template, start, end, accessLevel));
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -505,23 +502,25 @@
@Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
- enforcePermission(mCallingPackage);
- return internalGetSummaryForNetwork(template, start, end);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ return internalGetSummaryForNetwork(template, start, end, accessLevel);
}
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
- return internalGetHistoryForNetwork(template, fields);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ return internalGetHistoryForNetwork(template, fields, accessLevel);
}
@Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
- enforcePermissionForManagedAdmin(mCallingPackage);
- final NetworkStats stats = getUidComplete().getSummary(template, start, end);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ final NetworkStats stats =
+ getUidComplete().getSummary(template, start, end, accessLevel);
if (includeTags) {
final NetworkStats tagStats = getUidTagComplete()
- .getSummary(template, start, end);
+ .getSummary(template, start, end, accessLevel);
stats.combineAllValues(tagStats);
}
return stats;
@@ -530,11 +529,13 @@
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
- enforcePermissionForManagedAdmin(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields);
+ return getUidComplete().getHistory(template, uid, set, tag, fields,
+ accessLevel);
} else {
- return getUidTagComplete().getHistory(template, uid, set, tag, fields);
+ return getUidTagComplete().getHistory(template, uid, set, tag, fields,
+ accessLevel);
}
}
@@ -542,12 +543,13 @@
public NetworkStatsHistory getHistoryIntervalForUid(
NetworkTemplate template, int uid, int set, int tag, int fields,
long start, long end) {
- enforcePermissionForManagedAdmin(mCallingPackage);
+ @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields, start, end);
+ return getUidComplete().getHistory(template, uid, set, tag, fields, start, end,
+ accessLevel);
} else {
return getUidTagComplete().getHistory(template, uid, set, tag, fields,
- start, end);
+ start, end, accessLevel);
}
}
@@ -559,80 +561,42 @@
};
}
- private boolean hasAppOpsPermission(String callingPackage) {
- final int callingUid = Binder.getCallingUid();
- boolean appOpsAllow = false;
- if (callingPackage != null) {
- AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(
- Context.APP_OPS_SERVICE);
-
- final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
- callingUid, callingPackage);
- if (mode == AppOpsManager.MODE_DEFAULT) {
- // The default behavior here is to check if PackageManager has given the app
- // permission.
- final int permissionCheck = mContext.checkCallingPermission(
- Manifest.permission.PACKAGE_USAGE_STATS);
- appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED;
- }
- appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED);
- }
- return appOpsAllow;
+ private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) {
+ return NetworkStatsAccess.checkAccessLevel(
+ mContext, Binder.getCallingUid(), callingPackage);
}
- private void enforcePermissionForManagedAdmin(String callingPackage) {
- boolean hasPermission = hasAppOpsPermission(callingPackage);
- if (!hasPermission) {
- // Profile and device owners are exempt from permission checking.
- final int callingUid = Binder.getCallingUid();
- final DevicePolicyManagerInternal dpmi = LocalServices.getService(
- DevicePolicyManagerInternal.class);
-
- // Device owners are also profile owners so it is enough to check for that.
- if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid,
- DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) {
- return;
- }
- }
- if (!hasPermission) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- }
- }
-
- private void enforcePermission(String callingPackage) {
- boolean appOpsAllow = hasAppOpsPermission(callingPackage);
- if (!appOpsAllow) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
- }
- }
-
-
/**
* Return network summary, splicing between DEV and XT stats when
* appropriate.
*/
private NetworkStats internalGetSummaryForNetwork(
- NetworkTemplate template, long start, long end) {
+ NetworkTemplate template, long start, long end,
+ @NetworkStatsAccess.Level int accessLevel) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getSummary(template, start, end);
+ return mXtStatsCached.getSummary(template, start, end, accessLevel);
}
/**
* Return network history, splicing between DEV and XT stats when
* appropriate.
*/
- private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
+ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields,
+ @NetworkStatsAccess.Level int accessLevel) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
+ return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields, accessLevel);
}
@Override
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ // Special case - since this is for internal use only, don't worry about a full access level
+ // check and just require the signature/privileged permission.
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
assertBandwidthControlEnabled();
- return internalGetSummaryForNetwork(template, start, end).getTotalBytes();
+ return internalGetSummaryForNetwork(template, start, end, NetworkStatsAccess.Level.DEVICE)
+ .getTotalBytes();
}
@Override
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 1987214..ce18818 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -121,6 +121,11 @@
}
@Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof IConditionProvider;
+ }
+
+ @Override
public void onBootPhaseAppsCanStart() {
super.onBootPhaseAppsCanStart();
for (int i = 0; i < mSystemConditionProviders.size(); i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c7551c50..09e6647 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -42,6 +42,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -53,6 +54,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
@@ -93,6 +95,8 @@
// List of packages in restored setting across all mUserProfiles, for quick
// filtering upon package updates.
private ArraySet<String> mRestoredPackages = new ArraySet<>();
+ // State of current service categories
+ private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>();
// Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
@@ -137,6 +141,8 @@
abstract protected IInterface asInterface(IBinder binder);
+ abstract protected boolean checkType(IInterface service);
+
abstract protected void onServiceAdded(ManagedServiceInfo info);
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -165,7 +171,8 @@
if (filter != null && !filter.matches(info.component)) continue;
pw.println(" " + info.component
+ " (user " + info.userid + "): " + info.service
- + (info.isSystem?" SYSTEM":""));
+ + (info.isSystem?" SYSTEM":"")
+ + (info.isGuest(this)?" GUEST":""));
}
}
@@ -262,6 +269,58 @@
}
}
+ /**
+ * Add a service to our callbacks. The lifecycle of this service is managed externally,
+ * but unlike a system service, it should not be considered privledged.
+ * */
+ public void registerGuestService(ManagedServiceInfo guest) {
+ checkNotNull(guest.service);
+ checkType(guest.service);
+ if (registerServiceImpl(guest) != null) {
+ onServiceAdded(guest);
+ }
+ }
+
+ public void setCategoryState(String category, boolean enabled) {
+ synchronized (mMutex) {
+ final Boolean previous = mCategoryEnabled.put(category, enabled);
+ if (!(previous == null || previous != enabled)) {
+ return;
+ }
+
+ // State changed
+ if (DEBUG) {
+ Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category);
+ }
+
+ final int[] userIds = mUserProfiles.getCurrentProfileIds();
+ for (int userId : userIds) {
+ final Set<ComponentName> componentNames = queryPackageForServices(null,
+ userId, category);
+
+ // Disallow services not enabled in Settings
+ final ArraySet<ComponentName> userComponents =
+ loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
+ if (userComponents == null) {
+ componentNames.clear();
+ } else {
+ componentNames.retainAll(userComponents);
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Components for category " + category + ": " + componentNames);
+ }
+ for (ComponentName c : componentNames) {
+ if (enabled) {
+ registerServiceLocked(c, userId);
+ } else {
+ unregisterServiceLocked(c, userId);
+ }
+ }
+ }
+
+ }
+ }
private void rebuildRestoredPackages() {
mRestoredPackages.clear();
@@ -283,9 +342,9 @@
int userId) {
final ContentResolver cr = mContext.getContentResolver();
String settingValue = Settings.Secure.getStringForUser(
- cr,
- settingName,
- userId);
+ cr,
+ settingName,
+ userId);
if (TextUtils.isEmpty(settingValue))
return null;
String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
@@ -314,10 +373,10 @@
TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
final ContentResolver cr = mContext.getContentResolver();
Settings.Secure.putStringForUser(
- cr,
- settingName,
- value,
- userId);
+ cr,
+ settingName,
+ value,
+ userId);
}
/**
@@ -333,12 +392,20 @@
}
protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
+ return queryPackageForServices(packageName, userId, null);
+ }
+
+ protected Set<ComponentName> queryPackageForServices(String packageName, int userId,
+ String category) {
Set<ComponentName> installed = new ArraySet<>();
final PackageManager pm = mContext.getPackageManager();
Intent queryIntent = new Intent(mConfig.serviceInterface);
if (!TextUtils.isEmpty(packageName)) {
queryIntent.setPackage(packageName);
}
+ if (category != null) {
+ queryIntent.addCategory(category);
+ }
List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
queryIntent,
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -353,9 +420,9 @@
ComponentName component = new ComponentName(info.packageName, info.name);
if (!mConfig.bindPermission.equals(info.permission)) {
Slog.w(TAG, "Skipping " + getCaption() + " service "
- + info.packageName + "/" + info.name
- + ": it does not require the permission "
- + mConfig.bindPermission);
+ + info.packageName + "/" + info.name
+ + ": it does not require the permission "
+ + mConfig.bindPermission);
continue;
}
installed.add(component);
@@ -432,7 +499,7 @@
synchronized (mMutex) {
// Unbind automatically bound services, retain system services.
for (ManagedServiceInfo service : mServices) {
- if (!service.isSystem) {
+ if (!service.isSystem && !service.isGuest(this)) {
toRemove.add(service);
}
}
@@ -449,12 +516,22 @@
}
final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
+
+ // Remove components from disabled categories so that those services aren't run.
+ for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
+ if (!e.getValue()) {
+ Set<ComponentName> c = queryPackageForServices(null, userIds[i],
+ e.getKey());
+ add.removeAll(c);
+ }
+ }
+
toAdd.put(userIds[i], add);
newEnabled.addAll(userComponents);
for (int j = 0; j < userComponents.size(); j++) {
- final ComponentName component = userComponents.valueAt(i);
+ final ComponentName component = userComponents.valueAt(j);
newPackages.add(component.getPackageName());
}
}
@@ -488,93 +565,97 @@
* Version of registerService that takes the name of a service component to bind to.
*/
private void registerService(final ComponentName name, final int userid) {
+ synchronized (mMutex) {
+ registerServiceLocked(name, userid);
+ }
+ }
+
+ private void registerServiceLocked(final ComponentName name, final int userid) {
if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
- synchronized (mMutex) {
- final String servicesBindingTag = name.toString() + "/" + userid;
- if (mServicesBinding.contains(servicesBindingTag)) {
- // stop registering this thing already! we're working on it
- return;
- }
- mServicesBinding.add(servicesBindingTag);
+ final String servicesBindingTag = name.toString() + "/" + userid;
+ if (mServicesBinding.contains(servicesBindingTag)) {
+ // stop registering this thing already! we're working on it
+ return;
+ }
+ mServicesBinding.add(servicesBindingTag);
- final int N = mServices.size();
- for (int i = N - 1; i >= 0; i--) {
- final ManagedServiceInfo info = mServices.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- // cut old connections
- if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
- + info.service);
- removeServiceLocked(i);
- if (info.connection != null) {
- mContext.unbindService(info.connection);
- }
+ final int N = mServices.size();
+ for (int i = N - 1; i >= 0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ // cut old connections
+ if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
+ + info.service);
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ mContext.unbindService(info.connection);
}
}
+ }
- Intent intent = new Intent(mConfig.serviceInterface);
- intent.setComponent(name);
+ Intent intent = new Intent(mConfig.serviceInterface);
+ intent.setComponent(name);
- intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
+ intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
- final PendingIntent pendingIntent = PendingIntent.getActivity(
- mContext, 0, new Intent(mConfig.settingsAction), 0);
- intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
+ final PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext, 0, new Intent(mConfig.settingsAction), 0);
+ intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
- ApplicationInfo appInfo = null;
- try {
- appInfo = mContext.getPackageManager().getApplicationInfo(
- name.getPackageName(), 0);
- } catch (NameNotFoundException e) {
- // Ignore if the package doesn't exist we won't be able to bind to the service.
- }
- final int targetSdkVersion =
- appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
+ ApplicationInfo appInfo = null;
+ try {
+ appInfo = mContext.getPackageManager().getApplicationInfo(
+ name.getPackageName(), 0);
+ } catch (NameNotFoundException e) {
+ // Ignore if the package doesn't exist we won't be able to bind to the service.
+ }
+ final int targetSdkVersion =
+ appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
- try {
- if (DEBUG) Slog.v(TAG, "binding: " + intent);
- ServiceConnection serviceConnection = new ServiceConnection() {
- IInterface mService;
+ try {
+ if (DEBUG) Slog.v(TAG, "binding: " + intent);
+ ServiceConnection serviceConnection = new ServiceConnection() {
+ IInterface mService;
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- boolean added = false;
- ManagedServiceInfo info = null;
- synchronized (mMutex) {
- mServicesBinding.remove(servicesBindingTag);
- try {
- mService = asInterface(binder);
- info = newServiceInfo(mService, name,
- userid, false /*isSystem*/, this, targetSdkVersion);
- binder.linkToDeath(info, 0);
- added = mServices.add(info);
- } catch (RemoteException e) {
- // already dead
- }
- }
- if (added) {
- onServiceAdded(info);
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ boolean added = false;
+ ManagedServiceInfo info = null;
+ synchronized (mMutex) {
+ mServicesBinding.remove(servicesBindingTag);
+ try {
+ mService = asInterface(binder);
+ info = newServiceInfo(mService, name,
+ userid, false /*isSystem*/, this, targetSdkVersion);
+ binder.linkToDeath(info, 0);
+ added = mServices.add(info);
+ } catch (RemoteException e) {
+ // already dead
}
}
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- Slog.v(TAG, getCaption() + " connection lost: " + name);
+ if (added) {
+ onServiceAdded(info);
}
- };
- if (!mContext.bindServiceAsUser(intent,
- serviceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- new UserHandle(userid))) {
- mServicesBinding.remove(servicesBindingTag);
- Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
- return;
}
- } catch (SecurityException ex) {
- Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Slog.v(TAG, getCaption() + " connection lost: " + name);
+ }
+ };
+ if (!mContext.bindServiceAsUser(intent,
+ serviceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ new UserHandle(userid))) {
+ mServicesBinding.remove(servicesBindingTag);
+ Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
return;
}
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
+ return;
}
}
@@ -583,20 +664,24 @@
*/
private void unregisterService(ComponentName name, int userid) {
synchronized (mMutex) {
- final int N = mServices.size();
- for (int i = N - 1; i >= 0; i--) {
- final ManagedServiceInfo info = mServices.get(i);
- if (name.equals(info.component)
- && info.userid == userid) {
- removeServiceLocked(i);
- if (info.connection != null) {
- try {
- mContext.unbindService(info.connection);
- } catch (IllegalArgumentException ex) {
- // something happened to the service: we think we have a connection
- // but it's bogus.
- Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
- }
+ unregisterServiceLocked(name, userid);
+ }
+ }
+
+ private void unregisterServiceLocked(ComponentName name, int userid) {
+ final int N = mServices.size();
+ for (int i = N - 1; i >= 0; i--) {
+ final ManagedServiceInfo info = mServices.get(i);
+ if (name.equals(info.component)
+ && info.userid == userid) {
+ removeServiceLocked(i);
+ if (info.connection != null) {
+ try {
+ mContext.unbindService(info.connection);
+ } catch (IllegalArgumentException ex) {
+ // something happened to the service: we think we have a connection
+ // but it's bogus.
+ Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
}
}
}
@@ -639,11 +724,15 @@
private ManagedServiceInfo registerServiceImpl(final IInterface service,
final ComponentName component, final int userid) {
+ ManagedServiceInfo info = newServiceInfo(service, component, userid,
+ true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
+ return registerServiceImpl(info);
+ }
+
+ private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
synchronized (mMutex) {
try {
- ManagedServiceInfo info = newServiceInfo(service, component, userid,
- true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
- service.asBinder().linkToDeath(info, 0);
+ info.service.asBinder().linkToDeath(info, 0);
mServices.add(info);
return info;
} catch (RemoteException e) {
@@ -658,7 +747,7 @@
*/
private void unregisterServiceImpl(IInterface service, int userid) {
ManagedServiceInfo info = removeServiceImpl(service, userid);
- if (info != null && info.connection != null) {
+ if (info != null && info.connection != null && !info.isGuest(this)) {
mContext.unbindService(info.connection);
}
}
@@ -710,6 +799,10 @@
this.targetSdkVersion = targetSdkVersion;
}
+ public boolean isGuest(ManagedServices host) {
+ return ManagedServices.this != host;
+ }
+
@Override
public String toString() {
return new StringBuilder("ManagedServiceInfo[")
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e6a48a8..9dcccc4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,29 +16,31 @@
package com.android.server.notification;
-import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
-import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
-import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL;
import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL;
+import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
+import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL;
+import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK;
+import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR;
+import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION;
+import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED;
import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL;
import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED;
-import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION;
+import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
+import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
+import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
+import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
+import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import static android.service.notification.NotificationListenerService.TRIM_FULL;
import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
-import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -77,7 +79,6 @@
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -97,6 +98,7 @@
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
import android.service.notification.IStatusBarNotificationHolder;
+import android.service.notification.NotificationAssistantService;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationRankingUpdate;
import android.service.notification.StatusBarNotification;
@@ -113,7 +115,6 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-
import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
@@ -126,9 +127,10 @@
import com.android.server.notification.ManagedServices.ManagedServiceInfo;
import com.android.server.notification.ManagedServices.UserProfiles;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.vr.VrStateListener;
import libcore.io.IoUtils;
-
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -155,6 +157,7 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -168,11 +171,13 @@
// message codes
static final int MESSAGE_TIMEOUT = 2;
static final int MESSAGE_SAVE_POLICY_FILE = 3;
- static final int MESSAGE_RECONSIDER_RANKING = 4;
- static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
- static final int MESSAGE_SEND_RANKING_UPDATE = 6;
- static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
- static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
+ static final int MESSAGE_SEND_RANKING_UPDATE = 4;
+ static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
+ static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
+
+ // ranking thread messages
+ private static final int MESSAGE_RECONSIDER_RANKING = 1000;
+ private static final int MESSAGE_RANKING_SORT = 1001;
static final int LONG_DELAY = 3500; // 3.5 seconds
static final int SHORT_DELAY = 2000; // 2 seconds
@@ -210,6 +215,8 @@
AudioManagerInternal mAudioManagerInternal;
StatusBarManagerInternal mStatusBar;
Vibrator mVibrator;
+ private VrManagerInternal mVrManagerInternal;
+ private final NotificationVrListener mVrListener = new NotificationVrListener();
final IBinder mForegroundToken = new Binder();
private WorkerHandler mHandler;
@@ -280,11 +287,13 @@
private final UserProfiles mUserProfiles = new UserProfiles();
private NotificationListeners mListeners;
+ private NotificationAssistant mAssistant;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
+ private RankingHandler mRankingHandler;
private static class Archive {
final int mBufferSize;
@@ -737,6 +746,7 @@
}
}
mListeners.onPackagesChanged(queryReplace, pkgList);
+ mAssistant.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
mRankingHelper.onPackagesChanged(queryReplace, pkgList);
}
@@ -778,6 +788,7 @@
// Refresh managed services
mConditionProviders.onUserSwitched(user);
mListeners.onUserSwitched(user);
+ mAssistant.onUserSwitched(user);
mZenModeHelper.onUserSwitched(user);
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
mUserProfiles.updateCache(context);
@@ -820,6 +831,14 @@
}
}
+ private final class NotificationVrListener extends VrStateListener {
+ @Override
+ public void onVrStateChanged(final boolean enabled) {
+ mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS,
+ enabled);
+ }
+ }
+
private SettingsObserver mSettingsObserver;
private ZenModeHelper mZenModeHelper;
@@ -865,8 +884,9 @@
extractorNames = new String[0];
}
mUsageStats = new NotificationUsageStats(getContext());
+ mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
mRankingHelper = new RankingHelper(getContext(),
- new RankingWorkerHandler(mRankingThread.getLooper()),
+ mRankingHandler,
mUsageStats,
extractorNames);
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
@@ -881,7 +901,8 @@
void onZenModeChanged() {
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
getContext().sendBroadcastAsUser(
- new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL),
+ new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
synchronized(mNotificationList) {
updateInterruptionFilterLocked();
@@ -899,6 +920,7 @@
importOldBlockDb();
mListeners = new NotificationListeners();
+ mAssistant = new NotificationAssistant();
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1007,12 +1029,15 @@
// Grab our optional AudioService
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
+ mVrManagerInternal = getLocalService(VrManagerInternal.class);
+ mVrManagerInternal.registerListener(mVrListener);
mZenModeHelper.onSystemReady();
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
// This observer will force an update when observe is called, causing us to
// bind to listener services.
mSettingsObserver.observe();
mListeners.onBootPhaseAppsCanStart();
+ mAssistant.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
}
}
@@ -1251,6 +1276,21 @@
return mRankingHelper.getTopicImportance(pkg, uid, topic);
}
+ @Override
+ public void setAppImportance(String pkg, int uid, int importance) {
+ enforceSystemOrSystemUI("Caller not system or systemui");
+ setNotificationsEnabledForPackageImpl(pkg, uid,
+ importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+ mRankingHelper.setAppImportance(pkg, uid, importance);
+ savePolicyFile();
+ }
+
+ @Override
+ public boolean doesAppUseTopics(String pkg, int uid) {
+ enforceSystemOrSystemUI("Caller not system or systemui");
+ return mRankingHelper.doesAppUseTopics(pkg, uid);
+ }
+
/**
* System-only API for getting a list of current (i.e. not cleared) notifications.
*
@@ -1869,6 +1909,22 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ @Override
+ public void setImportanceFromAssistant(INotificationListener token, String key,
+ int importance, CharSequence explanation) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ synchronized (mNotificationList) {
+ mAssistant.checkServiceTokenLocked(token);
+ NotificationRecord n = mNotificationsByKey.get(key);
+ n.setImportance(importance, explanation);
+ mRankingHandler.requestSort();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
};
private String disableNotificationEffects(NotificationRecord record) {
@@ -2010,6 +2066,8 @@
pw.print(listener.component);
}
pw.println(')');
+ pw.println("\n Notification assistant:");
+ mAssistant.dump(pw, filter);
}
pw.println("\n Policy access:");
pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2048,12 +2106,12 @@
for (UserInfo user : UserManager.get(getContext()).getUsers()) {
final int userId = user.getUserHandle().getIdentifier();
final PackageManager packageManager = getContext().getPackageManager();
- List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId);
+ List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
final int packageCount = packages.size();
for (int p = 0; p < packageCount; p++) {
final String packageName = packages.get(p).packageName;
if (filter == null || filter.matches(packageName)) {
- final int uid = packageManager.getPackageUid(packageName, userId);
+ final int uid = packageManager.getPackageUidAsUser(packageName, userId);
if (!checkNotificationOp(packageName, uid)) {
packageNames.add(packageName);
}
@@ -2506,9 +2564,14 @@
updateLightsLocked();
}
if (buzz || beep || blink) {
- EventLogTags.writeNotificationAlert(record.getKey(),
- buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
- mHandler.post(mBuzzBeepBlinked);
+ if (((record.getSuppressedVisualEffects()
+ & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0)) {
+ if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
+ } else {
+ EventLogTags.writeNotificationAlert(record.getKey(),
+ buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+ mHandler.post(mBuzzBeepBlinked);
+ }
}
}
@@ -2659,7 +2722,7 @@
}
}
- private void handleRankingConfigChange() {
+ private void handleRankingSort() {
synchronized (mNotificationList) {
final int N = mNotificationList.size();
ArrayList<String> orderBefore = new ArrayList<String>(N);
@@ -2670,8 +2733,8 @@
visibilities[i] = r.getPackageVisibilityOverride();
mRankingHelper.extractSignals(r);
}
+ mRankingHelper.sort(mNotificationList);
for (int i = 0; i < N; i++) {
- mRankingHelper.sort(mNotificationList);
final NotificationRecord r = mNotificationList.get(i);
if (!orderBefore.get(i).equals(r.getKey())
|| visibilities[i] != r.getPackageVisibilityOverride()) {
@@ -2687,7 +2750,8 @@
record.setIntercepted(mZenModeHelper.shouldIntercept(record));
if (record.isIntercepted()) {
int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0)
- | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0);
+ | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0)
+ | (mZenModeHelper.shouldSuppressScreenOn() ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
record.setSuppressedVisualEffects(suppressed);
}
}
@@ -2761,9 +2825,9 @@
}
- private final class RankingWorkerHandler extends Handler
+ private final class RankingHandlerWorker extends Handler implements RankingHandler
{
- public RankingWorkerHandler(Looper looper) {
+ public RankingHandlerWorker(Looper looper) {
super(looper);
}
@@ -2773,11 +2837,23 @@
case MESSAGE_RECONSIDER_RANKING:
handleRankingReconsideration(msg);
break;
- case MESSAGE_RANKING_CONFIG_CHANGE:
- handleRankingConfigChange();
+ case MESSAGE_RANKING_SORT:
+ handleRankingSort();
break;
}
}
+
+ public void requestSort() {
+ removeMessages(MESSAGE_RANKING_SORT);
+ sendEmptyMessage(MESSAGE_RANKING_SORT);
+ }
+
+ public void requestReconsideration(RankingReconsideration recon) {
+ Message m = Message.obtain(this,
+ NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
+ long delay = recon.getDelay(TimeUnit.MILLISECONDS);
+ sendMessageDelayed(m, delay);
+ }
}
// Notifications
@@ -3278,6 +3354,45 @@
return true;
}
+ public class NotificationAssistant extends ManagedServices {
+
+ public NotificationAssistant() {
+ super(getContext(), mHandler, mNotificationList, mUserProfiles);
+ }
+
+ @Override
+ protected Config getConfig() {
+ Config c = new Config();
+ c.caption = "notification assistant";
+ c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+ c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+ c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+ c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
+ c.clientLabel = R.string.notification_assistant_binding_label;
+ return c;
+ }
+
+ @Override
+ protected IInterface asInterface(IBinder binder) {
+ return INotificationListener.Stub.asInterface(binder);
+ }
+
+ @Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof INotificationListener;
+ }
+
+ @Override
+ protected void onServiceAdded(ManagedServiceInfo info) {
+ mListeners.registerGuestService(info);
+ }
+
+ @Override
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+ mListeners.unregisterService(removed.service, removed.userid);
+ }
+ }
+
public class NotificationListeners extends ManagedServices {
private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
@@ -3305,6 +3420,11 @@
}
@Override
+ protected boolean checkType(IInterface service) {
+ return service instanceof INotificationListener;
+ }
+
+ @Override
public void onServiceAdded(ManagedServiceInfo info) {
final INotificationListener listener = (INotificationListener) info.service;
final NotificationRankingUpdate update;
@@ -3339,7 +3459,6 @@
public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
-
}
/**
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index acdd90a..9b10ef2 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -35,4 +35,8 @@
void setTopicImportance(String packageName, int uid, Notification.Topic topic, int importance);
int getTopicImportance(String packageName, int uid, Notification.Topic topic);
+
+ void setAppImportance(String packageName, int uid, int importance);
+
+ boolean doesAppUseTopics(String packageName, int uid);
}
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/services/core/java/com/android/server/notification/RankingHandler.java
similarity index 67%
copy from core/java/android/view/IDockDividerVisibilityListener.aidl
copy to services/core/java/com/android/server/notification/RankingHandler.java
index a7d5cda..80bb4f0 100644
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -13,15 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.android.server.notification;
-package android.view;
-
-/**
- * Listener for showing/hiding of the dock divider. Will fire when an app is shown in side by side
- * mode and a divider should be shown.
- *
- * @hide
- */
-oneway interface IDockDividerVisibilityListener {
- void onDockDividerVisibilityChanged(boolean visible);
+public interface RankingHandler {
+ public void requestSort();
+ public void requestReconsideration(RankingReconsideration recon);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 5a31c6a..f1fd42c 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,10 +19,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.Message;
import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -40,7 +37,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.TimeUnit;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -73,10 +69,10 @@
private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
private final Context mContext;
- private final Handler mRankingHandler;
+ private final RankingHandler mRankingHandler;
- public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
- String[] extractorNames) {
+ public RankingHelper(Context context, RankingHandler rankingHandler,
+ NotificationUsageStats usageStats, String[] extractorNames) {
mContext = context;
mRankingHandler = rankingHandler;
@@ -119,10 +115,7 @@
try {
RankingReconsideration recon = extractor.process(r);
if (recon != null) {
- Message m = Message.obtain(mRankingHandler,
- NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
- long delay = recon.getDelay(TimeUnit.MILLISECONDS);
- mRankingHandler.sendMessageDelayed(m, delay);
+ mRankingHandler.requestReconsideration(recon);
}
} catch (Throwable t) {
Slog.w(TAG, "NotificationSignalExtractor failed.", t);
@@ -155,7 +148,7 @@
if (forRestore) {
try {
//TODO: http://b/22388012
- uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM);
+ uid = pm.getPackageUidAsUser(name, UserHandle.USER_SYSTEM);
} catch (NameNotFoundException e) {
// noop
}
@@ -170,6 +163,7 @@
} else {
r = getOrCreateRecord(name, uid);
}
+ r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
// Migrate package level settings to the default topic.
// Might be overwritten by parseTopics.
@@ -251,6 +245,7 @@
}
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
+ out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
if (!forBackup) {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -285,7 +280,7 @@
for (int i = 0; i < N; i++) {
mSignalExtractors[i].setConfig(this);
}
- mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
+ mRankingHandler.requestSort();
}
public void sort(ArrayList<NotificationRecord> notificationList) {
@@ -426,6 +421,32 @@
updateConfig();
}
+ /**
+ * Sets the default importance for all new topics that appear in the future, and resets
+ * the importance of all current topics.
+ */
+ @Override
+ public void setAppImportance(String pkgName, int uid, int importance) {
+ final Record r = getOrCreateRecord(pkgName, uid);
+ r.importance = importance;
+ for (Topic t : r.topics.values()) {
+ t.importance = importance;
+ }
+ updateConfig();
+ }
+
+ @Override
+ public boolean doesAppUseTopics(String pkgName, int uid) {
+ final Record r = getOrCreateRecord(pkgName, uid);
+ int numTopics = r.topics.size();
+ if (numTopics == 0
+ || (numTopics == 1 && r.topics.containsKey(Notification.TOPIC_DEFAULT))) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
private Topic getOrCreateTopic(Record r, Notification.Topic topic) {
if (topic == null) {
topic = createDefaultTopic();
@@ -435,6 +456,7 @@
return t;
} else {
t = new Topic(topic);
+ t.importance = r.importance;
r.topics.put(topic.getId(), t);
return t;
}
@@ -477,6 +499,8 @@
pw.print(" (");
pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
+ pw.print(" importance=");
+ pw.print(Ranking.importanceToString(r.importance));
pw.println();
for (Topic t : r.topics.values()) {
pw.print(prefix);
@@ -513,7 +537,7 @@
if (r != null) {
try {
//TODO: http://b/22388012
- r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM);
+ r.uid = pm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM);
mRestoredWithoutUids.remove(pkg);
mRecords.put(recordKey(r.pkg, r.uid), r);
updated = true;
@@ -532,6 +556,7 @@
String pkg;
int uid = UNKNOWN_UID;
+ int importance = DEFAULT_IMPORTANCE;
Map<String, Topic> topics = new ArrayMap<>();
}
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index cee9ec8..9cdece5 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -109,7 +109,6 @@
if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
ZenModeConfig config = mHelper.getConfig();
if (config == null) return;
- config = config.copy();
boolean updated = updateCondition(id, condition, config.manualRule);
for (ZenRule automaticRule : config.automaticRules.values()) {
updated |= updateCondition(id, condition, automaticRule);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 6030bab..f7043a6 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -77,6 +77,9 @@
static final String TAG = "ZenModeHelper";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ // The amount of time rules instances can exist without their owning app being installed.
+ private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
+
private final Context mContext;
private final H mHandler;
private final SettingsObserver mSettingsObserver;
@@ -93,6 +96,7 @@
private int mUser = UserHandle.USER_SYSTEM;
private ZenModeConfig mConfig;
private AudioManagerInternal mAudioManager;
+ private PackageManager mPm;
private boolean mEffectsSuppressed;
public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
@@ -151,6 +155,12 @@
}
}
+ public boolean shouldSuppressScreenOn() {
+ synchronized (mConfig) {
+ return !mConfig.allowScreenOn;
+ }
+ }
+
public void addCallback(Callback callback) {
mCallbacks.add(callback);
}
@@ -170,7 +180,9 @@
if (mAudioManager != null) {
mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
}
+ mPm = mContext.getPackageManager();
mHandler.postMetricsTimer();
+ cleanUpZenRules();
evaluateZenMode("onSystemReady", true);
}
@@ -184,7 +196,10 @@
config = mDefaultConfig.copy();
config.user = user;
}
- setConfig(config, "onUserSwitched");
+ synchronized (mConfig) {
+ setConfig(config, "onUserSwitched");
+ }
+ cleanUpZenRules();
}
public void onUserRemoved(int user) {
@@ -253,14 +268,15 @@
throw new IllegalArgumentException("Rule already exists");
}
newConfig = mConfig.copy();
- }
- ZenRule rule = new ZenRule();
- populateZenRule(automaticZenRule, rule, true);
- newConfig.automaticRules.put(rule.id, rule);
- if (setConfig(newConfig, reason, true)) {
- return createAutomaticZenRule(rule);
- } else {
- return null;
+
+ ZenRule rule = new ZenRule();
+ populateZenRule(automaticZenRule, rule, true);
+ newConfig.automaticRules.put(rule.id, rule);
+ if (setConfig(newConfig, reason, true)) {
+ return createAutomaticZenRule(rule);
+ } else {
+ return null;
+ }
}
}
@@ -273,21 +289,21 @@
+ " reason=" + reason);
}
newConfig = mConfig.copy();
- }
- final String ruleId = automaticZenRule.getId();
- ZenModeConfig.ZenRule rule;
- if (ruleId == null) {
- throw new IllegalArgumentException("Rule doesn't exist");
- } else {
- rule = newConfig.automaticRules.get(ruleId);
- if (rule == null || !canManageAutomaticZenRule(rule)) {
- throw new SecurityException(
- "Cannot update rules not owned by your condition provider");
+ final String ruleId = automaticZenRule.getId();
+ ZenModeConfig.ZenRule rule;
+ if (ruleId == null) {
+ throw new IllegalArgumentException("Rule doesn't exist");
+ } else {
+ rule = newConfig.automaticRules.get(ruleId);
+ if (rule == null || !canManageAutomaticZenRule(rule)) {
+ throw new SecurityException(
+ "Cannot update rules not owned by your condition provider");
+ }
}
+ populateZenRule(automaticZenRule, rule, false);
+ newConfig.automaticRules.put(ruleId, rule);
+ return setConfig(newConfig, reason, true);
}
- populateZenRule(automaticZenRule, rule, false);
- newConfig.automaticRules.put(ruleId, rule);
- return setConfig(newConfig, reason, true);
}
public boolean removeAutomaticZenRule(String id, String reason) {
@@ -295,17 +311,17 @@
synchronized (mConfig) {
if (mConfig == null) return false;
newConfig = mConfig.copy();
+ ZenRule rule = newConfig.automaticRules.get(id);
+ if (rule == null) return false;
+ if (canManageAutomaticZenRule(rule)) {
+ newConfig.automaticRules.remove(id);
+ if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
+ } else {
+ throw new SecurityException(
+ "Cannot delete rules not owned by your condition provider");
+ }
+ return setConfig(newConfig, reason, true);
}
- ZenRule rule = newConfig.automaticRules.get(id);
- if (rule == null) return false;
- if (canManageAutomaticZenRule(rule)) {
- newConfig.automaticRules.remove(id);
- if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + id + " reason=" + reason);
- } else {
- throw new SecurityException(
- "Cannot delete rules not owned by your condition provider");
- }
- return setConfig(newConfig, reason, true);
}
public boolean removeAutomaticZenRules(String packageName, String reason) {
@@ -313,15 +329,15 @@
synchronized (mConfig) {
if (mConfig == null) return false;
newConfig = mConfig.copy();
- }
- for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
- ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (rule.component.getPackageName().equals(packageName)
- && canManageAutomaticZenRule(rule)) {
- newConfig.automaticRules.removeAt(i);
+ for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
+ ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
+ if (rule.component.getPackageName().equals(packageName)
+ && canManageAutomaticZenRule(rule)) {
+ newConfig.automaticRules.removeAt(i);
+ }
}
+ return setConfig(newConfig, reason, true);
}
- return setConfig(newConfig, reason, true);
}
public boolean canManageAutomaticZenRule(ZenRule rule) {
@@ -332,8 +348,7 @@
== PackageManager.PERMISSION_GRANTED) {
return true;
} else {
- String[] packages =
- mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
+ String[] packages = mPm.getPackagesForUid(Binder.getCallingUid());
if (packages != null) {
final int packageCount = packages.length;
for (int i = 0; i < packageCount; i++) {
@@ -384,22 +399,22 @@
+ " conditionId=" + conditionId + " reason=" + reason
+ " setRingerMode=" + setRingerMode);
newConfig = mConfig.copy();
- }
- if (zenMode == Global.ZEN_MODE_OFF) {
- newConfig.manualRule = null;
- for (ZenRule automaticRule : newConfig.automaticRules.values()) {
- if (automaticRule.isAutomaticActive()) {
- automaticRule.snoozing = true;
+ if (zenMode == Global.ZEN_MODE_OFF) {
+ newConfig.manualRule = null;
+ for (ZenRule automaticRule : newConfig.automaticRules.values()) {
+ if (automaticRule.isAutomaticActive()) {
+ automaticRule.snoozing = true;
+ }
}
+ } else {
+ final ZenRule newRule = new ZenRule();
+ newRule.enabled = true;
+ newRule.zenMode = zenMode;
+ newRule.conditionId = conditionId;
+ newConfig.manualRule = newRule;
}
- } else {
- final ZenRule newRule = new ZenRule();
- newRule.enabled = true;
- newRule.zenMode = zenMode;
- newRule.conditionId = conditionId;
- newConfig.manualRule = newRule;
+ setConfig(newConfig, reason, setRingerMode);
}
- setConfig(newConfig, reason, setRingerMode);
}
public void dump(PrintWriter pw, String prefix) {
@@ -426,11 +441,12 @@
return;
}
pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
- + "events=%s,reminders=%s,lights=%s,peek=%s)\n",
+ + "events=%s,reminders=%s,lights=%s,peek=%s,screenOn=%s)\n",
config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
config.allowRepeatCallers, config.allowMessages,
ZenModeConfig.sourceToString(config.allowMessagesFrom),
- config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek);
+ config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek,
+ config.allowScreenOn);
pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule);
if (config.automaticRules.isEmpty()) return;
final int N = config.automaticRules.size();
@@ -450,16 +466,20 @@
return;
}
config.manualRule = null; // don't restore the manual rule
+ long time = System.currentTimeMillis();
if (config.automaticRules != null) {
for (ZenRule automaticRule : config.automaticRules.values()) {
// don't restore transient state from restored automatic rules
automaticRule.snoozing = false;
automaticRule.condition = null;
+ automaticRule.creationTime = time;
}
}
}
if (DEBUG) Log.d(TAG, "readXml");
- setConfig(config, "readXml");
+ synchronized (mConfig) {
+ setConfig(config, "readXml");
+ }
}
}
@@ -484,11 +504,39 @@
public void setNotificationPolicy(Policy policy) {
if (policy == null || mConfig == null) return;
- final ZenModeConfig newConfig = mConfig.copy();
- newConfig.applyNotificationPolicy(policy);
- setConfig(newConfig, "setNotificationPolicy");
+ synchronized (mConfig) {
+ final ZenModeConfig newConfig = mConfig.copy();
+ newConfig.applyNotificationPolicy(policy);
+ setConfig(newConfig, "setNotificationPolicy");
+ }
}
+ /**
+ * Removes old rule instances whose owner is not installed.
+ */
+ private void cleanUpZenRules() {
+ long currentTime = System.currentTimeMillis();
+ synchronized (mConfig) {
+ final ZenModeConfig newConfig = mConfig.copy();
+ if (newConfig.automaticRules != null) {
+ for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
+ ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
+ if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
+ try {
+ mPm.getPackageInfo(rule.component.getPackageName(), 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ newConfig.automaticRules.removeAt(i);
+ }
+ }
+ }
+ }
+ setConfig(newConfig, "cleanUpZenRules");
+ }
+ }
+
+ /**
+ * @return a copy of the zen mode configuration
+ */
public ZenModeConfig getConfig() {
synchronized (mConfig) {
return mConfig.copy();
@@ -517,20 +565,18 @@
return true;
}
mConditions.evaluateConfig(config, false /*processSubscriptions*/); // may modify config
- synchronized (mConfig) {
- mConfigs.put(config.user, config);
- if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
- ZenLog.traceConfig(reason, mConfig, config);
- final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
- getNotificationPolicy(config));
- mConfig = config;
- if (config.equals(mConfig)) {
- dispatchOnConfigChanged();
- }
- if (policyChanged) {
- dispatchOnPolicyChanged();
- }
+ mConfigs.put(config.user, config);
+ if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
+ ZenLog.traceConfig(reason, mConfig, config);
+ final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
+ getNotificationPolicy(config));
+ if (!config.equals(mConfig)) {
+ dispatchOnConfigChanged();
}
+ if (policyChanged) {
+ dispatchOnPolicyChanged();
+ }
+ mConfig = config;
final String val = Integer.toString(config.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
if (!evaluateZenMode(reason, setRingerMode)) {
@@ -994,7 +1040,9 @@
break;
case MSG_SET_CONFIG:
ConfigMessageData configData = (ConfigMessageData)msg.obj;
- setConfig(configData.config, configData.reason);
+ synchronized (mConfig) {
+ setConfig(configData.config, configData.reason);
+ }
break;
}
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 073b4f03..6c338c1 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -57,7 +57,7 @@
private static final String TAG = "DefaultPermGrantPolicy"; // must be <= 23 chars
private static final boolean DEBUG = false;
- private static final int DEFAULT_FLAGS = PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS;
+ private static final int DEFAULT_FLAGS = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
private static final String AUDIO_MIME_TYPE = "audio/mpeg";
@@ -261,6 +261,7 @@
&& doesPackageSupportRuntimePermissions(setupPackage)) {
grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId);
grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId);
+ grantRuntimePermissionsLPw(setupPackage, LOCATION_PERMISSIONS, userId);
}
// Camera
@@ -594,6 +595,14 @@
}
}
+ // Print Spooler
+ PackageParser.Package printSpoolerPackage = getSystemPackageLPr(
+ "com.android.printspooler");
+ if (printSpoolerPackage != null
+ && doesPackageSupportRuntimePermissions(printSpoolerPackage)) {
+ grantRuntimePermissionsLPw(printSpoolerPackage, LOCATION_PERMISSIONS, true, userId);
+ }
+
mService.mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
}
}
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 628ad0e..fe6fb1f 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.EphemeralResolveInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
@@ -30,7 +31,6 @@
import android.util.TimedRemoteCaller;
import com.android.internal.app.EphemeralResolverService;
-import com.android.internal.app.EphemeralResolveInfo;
import com.android.internal.app.IEphemeralResolver;
import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index fa0aa37..66d10b5 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -482,7 +482,6 @@
throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
"Failed to resolve stage location", e);
}
- final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
// Verify that stage looks sane with respect to existing application.
// This currently only ensures packageName, versionCode, and certificate
@@ -490,10 +489,7 @@
validateInstallLocked();
Preconditions.checkNotNull(mPackageName);
- // TODO: fix b/25118622; don't bypass signature check
- if (!quickInstall) {
- Preconditions.checkNotNull(mSignatures);
- }
+ Preconditions.checkNotNull(mSignatures);
Preconditions.checkNotNull(mResolvedBaseFile);
if (!mPermissionsAccepted) {
@@ -603,7 +599,6 @@
* {@link PackageManagerService}.
*/
private void validateInstallLocked() throws PackageManagerException {
- final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
mPackageName = null;
mVersionCode = -1;
mSignatures = null;
@@ -627,9 +622,7 @@
final ApkLite apk;
try {
- // TODO: fix b/25118622; always use PARSE_COLLECT_CERTIFICATES
- final int parseFlags = quickInstall ? 0 : PackageParser.PARSE_COLLECT_CERTIFICATES;
- apk = PackageParser.parseApkLite(file, parseFlags);
+ apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -750,7 +743,6 @@
}
private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
- final boolean quickInstall = (params.installFlags & PackageManager.INSTALL_QUICK) != 0;
if (!mPackageName.equals(apk.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag + " package "
+ apk.packageName + " inconsistent with " + mPackageName);
@@ -760,8 +752,7 @@
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
}
- // TODO: fix b/25118622; don't bypass signature check
- if (!quickInstall && !Signature.areExactMatch(mSignatures, apk.signatures)) {
+ if (!Signature.areExactMatch(mSignatures, apk.signatures)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
tag + " signatures are inconsistent");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e0f85c5..9e0f3ce 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -54,11 +54,15 @@
import static android.content.pm.PackageManager.INSTALL_INTERNAL;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.MATCH_ALL;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
+import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
@@ -71,6 +75,7 @@
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDWR;
+
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE;
import static com.android.internal.app.IntentForwarderActivity.FORWARD_INTENT_TO_PARENT;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
@@ -87,6 +92,8 @@
import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -105,7 +112,10 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.AppsQueryHelper;
+import android.content.pm.ComponentInfo;
import android.content.pm.EphemeralApplicationInfo;
+import android.content.pm.EphemeralResolveInfo;
+import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
@@ -119,7 +129,6 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
@@ -148,10 +157,10 @@
import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.net.Uri;
-import android.os.Debug;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.FileUtils;
@@ -202,15 +211,8 @@
import android.util.Xml;
import android.view.Display;
-import com.android.internal.annotations.GuardedBy;
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
import com.android.internal.R;
-import com.android.internal.app.EphemeralResolveInfo;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
@@ -235,6 +237,12 @@
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import dalvik.system.DexFile;
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -305,6 +313,7 @@
private static final boolean DEBUG_DEXOPT = false;
private static final boolean DEBUG_ABI_SELECTION = false;
private static final boolean DEBUG_EPHEMERAL = false;
+ private static final boolean DEBUG_TRIAGED_MISSING = false;
static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
@@ -593,7 +602,9 @@
boolean mResolverReplaced = false;
- private final ComponentName mIntentFilterVerifierComponent;
+ private final @Nullable ComponentName mIntentFilterVerifierComponent;
+ private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier;
+
private int mIntentFilterVerificationToken = 0;
/** Component that knows whether or not an ephemeral application exists */
@@ -804,7 +815,7 @@
packageName);
}
if (DEBUG_DOMAIN_VERIFICATION) {
- Slog.d(TAG, "Adding verification filter for " + packageName + " : " + filter);
+ Slog.d(TAG, "Adding verification filter for " + packageName + ": " + filter);
}
ivs.addFilter(filter);
return true;
@@ -829,8 +840,6 @@
filter.hasDataScheme(IntentFilter.SCHEME_HTTPS));
}
- private IntentFilterVerifier mIntentFilterVerifier;
-
// Set of pending broadcasts for aggregating enable/disable of components.
static class PendingPackageBroadcasts {
// for each user id, a map of <package name -> components within that package>
@@ -965,8 +974,8 @@
private static final String TAG_DEFAULT_APPS = "da";
private static final String TAG_INTENT_FILTER_VERIFICATION = "iv";
- final String mRequiredVerifierPackage;
- final String mRequiredInstallerPackage;
+ final @Nullable String mRequiredVerifierPackage;
+ final @Nullable String mRequiredInstallerPackage;
private final PackageUsage mPackageUsage = new PackageUsage();
@@ -1843,12 +1852,12 @@
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
- m.enableSystemUserApps();
+ m.enableSystemUserPackages();
ServiceManager.addService("package", m);
return m;
}
- private void enableSystemUserApps() {
+ private void enableSystemUserPackages() {
if (!UserManager.isSplitSystemUser()) {
return;
}
@@ -1865,48 +1874,32 @@
| AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
enableApps.addAll(wlApps);
+ enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER,
+ /* systemAppsOnly */ false, UserHandle.SYSTEM));
ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
enableApps.removeAll(blApps);
-
- List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
+ Log.i(TAG, "Applications installed for system user: " + enableApps);
+ List<String> allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false,
UserHandle.SYSTEM);
- final int systemAppsSize = systemApps.size();
+ final int allAppsSize = allAps.size();
synchronized (mPackages) {
- for (int i = 0; i < systemAppsSize; i++) {
- String pName = systemApps.get(i);
+ for (int i = 0; i < allAppsSize; i++) {
+ String pName = allAps.get(i);
PackageSetting pkgSetting = mSettings.mPackages.get(pName);
// Should not happen, but we shouldn't be failing if it does
if (pkgSetting == null) {
continue;
}
- boolean installed = enableApps.contains(pName);
- pkgSetting.setInstalled(installed, UserHandle.USER_SYSTEM);
+ boolean install = enableApps.contains(pName);
+ if (pkgSetting.getInstalled(UserHandle.USER_SYSTEM) != install) {
+ Log.i(TAG, (install ? "Installing " : "Uninstalling ") + pName
+ + " for system user");
+ pkgSetting.setInstalled(install, UserHandle.USER_SYSTEM);
+ }
}
}
}
- static String[] splitString(String str, char sep) {
- int count = 1;
- int i = 0;
- while ((i=str.indexOf(sep, i)) >= 0) {
- count++;
- i++;
- }
-
- String[] res = new String[count];
- i=0;
- count = 0;
- int lastI=0;
- while ((i=str.indexOf(sep, i)) >= 0) {
- res[count] = str.substring(lastI, i);
- count++;
- i++;
- lastI = i;
- }
- res[count] = str.substring(lastI, str.length());
- return res;
- }
-
private static void getDefaultDisplayMetrics(Context context, DisplayMetrics metrics) {
DisplayManager displayManager = (DisplayManager) context.getSystemService(
Context.DISPLAY_SERVICE);
@@ -2369,15 +2362,21 @@
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
- mRequiredVerifierPackage = getRequiredVerifierLPr();
- mRequiredInstallerPackage = getRequiredInstallerLPr();
+ if (!mOnlyCore) {
+ mRequiredVerifierPackage = getRequiredVerifierLPr();
+ mRequiredInstallerPackage = getRequiredInstallerLPr();
+ mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
+ mIntentFilterVerifier = new IntentVerifierProxy(mContext,
+ mIntentFilterVerifierComponent);
+ } else {
+ mRequiredVerifierPackage = null;
+ mRequiredInstallerPackage = null;
+ mIntentFilterVerifierComponent = null;
+ mIntentFilterVerifier = null;
+ }
mInstallerService = new PackageInstallerService(context, this);
- mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
- mIntentFilterVerifier = new IntentVerifierProxy(mContext,
- mIntentFilterVerifierComponent);
-
final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
// both the installer and resolver must be present to enable ephemeral
@@ -2439,113 +2438,60 @@
return mIsUpgrade;
}
- private String getRequiredVerifierLPr() {
- final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- // We only care about verifier that's installed under system user.
- final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
- PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
+ private @NonNull String getRequiredVerifierLPr() {
+ final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
- String requiredVerifier = null;
-
- final int N = receivers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = receivers.get(i);
-
- if (info.activityInfo == null) {
- continue;
- }
-
- final String packageName = info.activityInfo.packageName;
-
- if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
- packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
- continue;
- }
-
- if (requiredVerifier != null) {
- throw new RuntimeException("There can be only one required verifier");
- }
-
- requiredVerifier = packageName;
+ final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ throw new RuntimeException("There must be exactly one verifier; found " + matches);
}
-
- return requiredVerifier;
}
- private String getRequiredInstallerLPr() {
- Intent installerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
- installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
- installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
+ private @NonNull String getRequiredInstallerLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
- PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM);
-
- String requiredInstaller = null;
-
- final int N = installers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = installers.get(i);
- final String packageName = info.activityInfo.packageName;
-
- if (!info.activityInfo.applicationInfo.isSystemApp()) {
- continue;
- }
-
- if (requiredInstaller != null) {
- throw new RuntimeException("There must be one required installer");
- }
-
- requiredInstaller = packageName;
+ final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().packageName;
+ } else {
+ throw new RuntimeException("There must be exactly one installer; found " + matches);
}
-
- if (requiredInstaller == null) {
- throw new RuntimeException("There must be one required installer");
- }
-
- return requiredInstaller;
}
- private ComponentName getIntentFilterVerifierComponentNameLPr() {
- final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
- final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
- PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
+ private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
- ComponentName verifierComponentName = null;
-
- int priority = -1000;
- final int N = receivers.size();
+ final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ ResolveInfo best = null;
+ final int N = matches.size();
for (int i = 0; i < N; i++) {
- final ResolveInfo info = receivers.get(i);
-
- if (info.activityInfo == null) {
- continue;
- }
-
- final String packageName = info.activityInfo.packageName;
-
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
- continue;
- }
-
+ final ResolveInfo cur = matches.get(i);
+ final String packageName = cur.getComponentInfo().packageName;
if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
continue;
}
- // Select the IntentFilterVerifier with the highest priority
- if (priority < info.priority) {
- priority = info.priority;
- verifierComponentName = new ComponentName(packageName, info.activityInfo.name);
- if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Selecting IntentFilterVerifier: "
- + verifierComponentName + " with priority: " + info.priority);
+ if (best == null || cur.priority > best.priority) {
+ best = cur;
}
}
- return verifierComponentName;
+ if (best != null) {
+ return best.getComponentInfo().getComponentName();
+ } else {
+ throw new RuntimeException("There must be at least one intent filter verifier");
+ }
}
- private ComponentName getEphemeralResolverLPr() {
+ private @Nullable ComponentName getEphemeralResolverLPr() {
final String[] packageArray =
mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
if (packageArray.length == 0) {
@@ -2555,9 +2501,9 @@
return null;
}
- Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
- final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent,
- null /*resolvedType*/, 0 /*flags*/, UserHandle.USER_SYSTEM);
+ final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
+ final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, null,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
final int N = resolvers.size();
if (N == 0) {
@@ -2596,36 +2542,21 @@
return null;
}
- private ComponentName getEphemeralInstallerLPr() {
- Intent installerIntent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
- installerIntent.addCategory(Intent.CATEGORY_DEFAULT);
- installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
- PACKAGE_MIME_TYPE, 0 /*flags*/, 0 /*userId*/);
+ private @Nullable ComponentName getEphemeralInstallerLPr() {
+ final Intent intent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
- ComponentName ephemeralInstaller = null;
-
- final int N = installers.size();
- for (int i = 0; i < N; i++) {
- final ResolveInfo info = installers.get(i);
- final String packageName = info.activityInfo.packageName;
-
- if (!info.activityInfo.applicationInfo.isSystemApp()) {
- if (DEBUG_EPHEMERAL) {
- Slog.d(TAG, "Ephemeral installer is not system app;"
- + " pkg: " + packageName + ", info:" + info);
- }
- continue;
- }
-
- if (ephemeralInstaller != null) {
- throw new RuntimeException("There must only be one ephemeral installer");
- }
-
- ephemeralInstaller = new ComponentName(packageName, info.activityInfo.name);
+ final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE,
+ MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM);
+ if (matches.size() == 0) {
+ return null;
+ } else if (matches.size() == 1) {
+ return matches.get(0).getComponentInfo().getComponentName();
+ } else {
+ throw new RuntimeException(
+ "There must be at most one ephemeral installer; found " + matches);
}
-
- return ephemeralInstaller;
}
private void primeDomainVerificationsLPw(int userId) {
@@ -2672,7 +2603,7 @@
+ "' does not handle web links");
}
} else {
- Slog.w(TAG, "Unknown package '" + packageName + "' in sysconfig <app-link>");
+ Slog.w(TAG, "Unknown package " + packageName + " in sysconfig <app-link>");
}
}
@@ -2860,6 +2791,7 @@
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
// reader
synchronized (mPackages) {
@@ -2869,7 +2801,7 @@
if (p != null) {
return generatePackageInfo(p, flags, userId);
}
- if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
return generatePackageInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -2910,6 +2842,7 @@
@Override
public int getPackageUidEtc(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return -1;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
// reader
@@ -2918,7 +2851,7 @@
if (p != null) {
return UserHandle.getUid(userId, p.applicationInfo.uid);
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
return UserHandle.getUid(userId, ps.appId);
@@ -2936,10 +2869,8 @@
@Override
public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
- if (!sUserManager.exists(userId)) {
- return null;
- }
-
+ if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
"getPackageGids");
@@ -2950,7 +2881,7 @@
PackageSetting ps = (PackageSetting) p.mExtras;
return ps.getPermissionsState().computeGids(userId);
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps != null) {
return ps.getPermissionsState().computeGids(userId);
@@ -2961,8 +2892,7 @@
return null;
}
- static PermissionInfo generatePermissionInfo(
- BasePermission bp, int flags) {
+ static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
if (bp.perm != null) {
return PackageParser.generatePermissionInfo(bp.perm, flags);
}
@@ -3059,7 +2989,7 @@
if (ps != null) {
PackageParser.Package pkg = ps.pkg;
if (pkg == null) {
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) {
return null;
}
// Only data remains, so we aren't worried about code paths
@@ -3080,6 +3010,7 @@
@Override
public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
+ flags = updateFlagsForApplication(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
// writer
synchronized (mPackages) {
@@ -3097,7 +3028,7 @@
if ("android".equals(packageName)||"system".equals(packageName)) {
return mAndroidApplication;
}
- if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+ if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
return generateApplicationInfoFromSettingsLPw(packageName, flags, userId);
}
}
@@ -3194,26 +3125,94 @@
}
/**
- * Augment the given flags depending on current user running state. This is
- * purposefully done before acquiring {@link #mPackages} lock.
+ * Update given flags based on encryption status of current user.
*/
- private int augmentFlagsForUser(int flags, int userId) {
- if (!isUserKeyUnlocked(userId)) {
- flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
+ private int updateFlagsForEncryption(int flags, int userId) {
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
+ // Caller expressed an explicit opinion about what encryption
+ // aware/unaware components they want to see, so fall through and
+ // give them what they want
+ } else {
+ // Caller expressed no opinion, so match based on user state
+ if (isUserKeyUnlocked(userId)) {
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+ } else {
+ flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
+ }
}
return flags;
}
+ /**
+ * Update given flags when being used to request {@link PackageInfo}.
+ */
+ private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+ boolean triaged = true;
+ if ((flags & PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+ | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS) != 0) {
+ // Caller is asking for component details, so they'd better be
+ // asking for specific encryption matching behavior, or be triaged
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ }
+ if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+ Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+ new Throwable());
+ }
+ return updateFlagsForEncryption(flags, userId);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ApplicationInfo}.
+ */
+ private int updateFlagsForApplication(int flags, int userId, Object cookie) {
+ return updateFlagsForPackage(flags, userId, cookie);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ComponentInfo}.
+ */
+ private int updateFlagsForComponent(int flags, int userId, Object cookie) {
+ boolean triaged = true;
+ // Caller is asking for component details, so they'd better be
+ // asking for specific encryption matching behavior, or be triaged
+ if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+ | PackageManager.MATCH_ENCRYPTION_AWARE
+ | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+ triaged = false;
+ }
+ if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+ Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+ new Throwable());
+ }
+ return updateFlagsForEncryption(flags, userId);
+ }
+
+ /**
+ * Update given flags when being used to request {@link ResolveInfo}.
+ */
+ private int updateFlagsForResolve(int flags, int userId, Object cookie) {
+ return updateFlagsForComponent(flags, userId, cookie);
+ }
+
@Override
public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
synchronized (mPackages) {
PackageParser.Activity a = mActivities.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
+ if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3252,13 +3251,13 @@
@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
synchronized (mPackages) {
PackageParser.Activity a = mReceivers.mActivities.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getReceiverInfo " + component + ": " + a);
- if (a != null && mSettings.isEnabledAndVisibleLPr(a.info, flags, userId)) {
+ if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
@@ -3271,13 +3270,13 @@
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
- if (s != null && mSettings.isEnabledAndVisibleLPr(s.info, flags, userId)) {
+ if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
@@ -3290,13 +3289,13 @@
@Override
public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, component);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
synchronized (mPackages) {
PackageParser.Provider p = mProviders.mProviders.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getProviderInfo " + component + ": " + p);
- if (p != null && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)) {
+ if (p != null && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
return PackageParser.generateProviderInfo(p, flags, ps.readUserState(userId),
@@ -3718,8 +3717,8 @@
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot grant system fixed permission: "
- + name + " for package: " + packageName);
+ throw new SecurityException("Cannot grant system fixed permission "
+ + name + " for package " + packageName);
}
if (bp.isDevelopment()) {
@@ -3827,8 +3826,8 @@
final int flags = permissionsState.getPermissionFlags(name, userId);
if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) {
- throw new SecurityException("Cannot revoke system fixed permission: "
- + name + " for package: " + packageName);
+ throw new SecurityException("Cannot revoke system fixed permission "
+ + name + " for package " + packageName);
}
if (bp.isDevelopment()) {
@@ -4415,10 +4414,24 @@
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
- return chooseBestActivity(intent, resolvedType, flags, query, userId);
+ final ResolveInfo bestChoice =
+ chooseBestActivity(intent, resolvedType, flags, query, userId);
+
+ if (isEphemeralAllowed(intent, query, userId)) {
+ final EphemeralResolveInfo ai =
+ getEphemeralResolveInfo(intent, resolvedType, userId);
+ if (ai != null) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "Returning an EphemeralResolveInfo");
+ }
+ bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
+ bestChoice.ephemeralResolveInfo = ai;
+ }
+ }
+ return bestChoice;
}
@Override
@@ -4453,13 +4466,61 @@
false, false, false, userId);
}
- private boolean isEphemeralAvailable(Intent intent, String resolvedType, int userId) {
+
+ private boolean isEphemeralAllowed(
+ Intent intent, List<ResolveInfo> resolvedActivites, int userId) {
+ // Short circuit and return early if possible.
+ final int callingUser = UserHandle.getCallingUserId();
+ if (callingUser != UserHandle.USER_SYSTEM) {
+ return false;
+ }
+ if (mEphemeralResolverConnection == null) {
+ return false;
+ }
+ if (intent.getComponent() != null) {
+ return false;
+ }
+ if (intent.getPackage() != null) {
+ return false;
+ }
+ final boolean isWebUri = hasWebURI(intent);
+ if (!isWebUri) {
+ return false;
+ }
+ // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
+ synchronized (mPackages) {
+ final int count = resolvedActivites.size();
+ for (int n = 0; n < count; n++) {
+ ResolveInfo info = resolvedActivites.get(n);
+ String packageName = info.activityInfo.packageName;
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps != null) {
+ // Try to get the status from User settings first
+ long packedStatus = getDomainVerificationStatusLPr(ps, userId);
+ int status = (int) (packedStatus >> 32);
+ if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
+ || status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
+ if (DEBUG_EPHEMERAL) {
+ Slog.v(TAG, "DENY ephemeral apps;"
+ + " pkg: " + packageName + ", status: " + status);
+ }
+ return false;
+ }
+ }
+ }
+ }
+ // We've exhausted all ways to deny ephemeral application; let the system look for them.
+ return true;
+ }
+
+ private EphemeralResolveInfo getEphemeralResolveInfo(Intent intent, String resolvedType,
+ int userId) {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance(EphemeralResolveInfo.SHA_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
// If we can't create a digest, ignore ephemeral apps.
- return false;
+ return null;
}
final byte[] hostBytes = intent.getData().getHost().getBytes();
@@ -4473,7 +4534,7 @@
mEphemeralResolverConnection.getEphemeralResolveInfoList(shaPrefix);
if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
// No hash prefix match; there are no ephemeral apps for this domain.
- return false;
+ return null;
}
for (int i = ephemeralResolveInfoList.size() - 1; i >= 0; --i) {
EphemeralResolveInfo ephemeralApplication = ephemeralResolveInfoList.get(i);
@@ -4488,62 +4549,22 @@
// We have a domain match; resolve the filters to see if anything matches.
final EphemeralIntentResolver ephemeralResolver = new EphemeralIntentResolver();
for (int j = filters.size() - 1; j >= 0; --j) {
- ephemeralResolver.addFilter(filters.get(j));
+ final EphemeralResolveIntentInfo intentInfo =
+ new EphemeralResolveIntentInfo(filters.get(j), ephemeralApplication);
+ ephemeralResolver.addFilter(intentInfo);
}
- List<ResolveInfo> ephemeralResolveList = ephemeralResolver.queryIntent(
+ List<EphemeralResolveInfo> matchedResolveInfoList = ephemeralResolver.queryIntent(
intent, resolvedType, false /*defaultOnly*/, userId);
- return !ephemeralResolveList.isEmpty();
+ if (!matchedResolveInfoList.isEmpty()) {
+ return matchedResolveInfoList.get(0);
+ }
}
// Hash or filter mis-match; no ephemeral apps for this domain.
- return false;
+ return null;
}
private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, int userId) {
- final boolean isWebUri = hasWebURI(intent);
- // Check whether or not an ephemeral app exists to handle the URI.
- if (isWebUri && mEphemeralResolverConnection != null) {
- // Deny ephemeral apps if the user choose _ALWAYS or _ALWAYS_ASK for intent resolution.
- boolean hasAlwaysHandler = false;
- synchronized (mPackages) {
- final int count = query.size();
- for (int n=0; n<count; n++) {
- ResolveInfo info = query.get(n);
- String packageName = info.activityInfo.packageName;
- PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
- // Try to get the status from User settings first
- long packedStatus = getDomainVerificationStatusLPr(ps, userId);
- int status = (int) (packedStatus >> 32);
- if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS
- || status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK) {
- hasAlwaysHandler = true;
- break;
- }
- }
- }
- }
-
- // Only consider installing an ephemeral app if there isn't already a verified handler.
- // We've determined that there's an ephemeral app available for the URI, ignore any
- // ResolveInfo's and just return the ephemeral installer
- if (!hasAlwaysHandler && isEphemeralAvailable(intent, resolvedType, userId)) {
- if (DEBUG_EPHEMERAL) {
- Slog.v(TAG, "Resolving to the ephemeral installer");
- }
- // ditch the result and return a ResolveInfo to launch the ephemeral installer
- ResolveInfo ri = new ResolveInfo(mEphemeralInstallerInfo);
- ri.activityInfo = new ActivityInfo(ri.activityInfo);
- // make a deep copy of the applicationInfo
- ri.activityInfo.applicationInfo = new ApplicationInfo(
- ri.activityInfo.applicationInfo);
- if (userId != 0) {
- ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId,
- UserHandle.getAppId(ri.activityInfo.applicationInfo.uid));
- }
- return ri;
- }
- }
if (query != null) {
final int N = query.size();
if (N == 1) {
@@ -4559,7 +4580,7 @@
+ r1.activityInfo.name + "=" + r1.priority);
}
// If the first activity has a higher priority, or a different
- // default, then it is always desireable to pick it.
+ // default, then it is always desirable to pick it.
if (r0.priority != r1.priority
|| r0.preferredOrder != r1.preferredOrder
|| r0.isDefault != r1.isDefault) {
@@ -4611,7 +4632,7 @@
ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
}
final ActivityInfo ai = getActivityInfo(ppa.mComponent,
- flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ flags | MATCH_DISABLED_COMPONENTS, userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found persistent preferred activity:");
if (ai != null) {
@@ -4651,7 +4672,7 @@
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
// writer
synchronized (mPackages) {
if (intent.getSelector() != null) {
@@ -4720,7 +4741,7 @@
continue;
}
final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent,
- flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ flags | MATCH_DISABLED_COMPONENTS, userId);
if (DEBUG_PREFERRED || debug) {
Slog.v(TAG, "Found preferred activity:");
if (ai != null) {
@@ -4850,7 +4871,7 @@
public List<ResolveInfo> queryIntentActivities(Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
ComponentName comp = intent.getComponent();
if (comp == null) {
@@ -5334,7 +5355,7 @@
Intent[] specifics, String[] specificTypes, Intent intent,
String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
false, "query intent activity options");
final String resultsAction = intent.getAction();
@@ -5507,7 +5528,7 @@
public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5544,7 +5565,7 @@
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
@@ -5560,7 +5581,7 @@
public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5598,7 +5619,7 @@
public List<ResolveInfo> queryIntentContentProviders(
Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return Collections.emptyList();
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForResolve(flags, userId, intent);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -5634,8 +5655,9 @@
@Override
public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
-
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForPackage(flags, userId, null);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
// writer
@@ -5714,9 +5736,9 @@
@Override
public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
String[] permissions, int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForPackage(flags, userId, permissions);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -5742,9 +5764,9 @@
@Override
public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
- if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
- final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
+ if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+ flags = updateFlagsForApplication(flags, userId, null);
+ final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
// writer
synchronized (mPackages) {
@@ -5886,7 +5908,7 @@
@Override
public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, name);
// reader
synchronized (mPackages) {
final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5894,7 +5916,7 @@
? mSettings.mPackages.get(provider.owner.packageName)
: null;
return ps != null
- && mSettings.isEnabledAndVisibleLPr(provider.info, flags, userId)
+ && mSettings.isEnabledAndMatchLPr(provider.info, flags, userId)
&& (!mSafeMode || (provider.info.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) != 0)
? PackageParser.generateProviderInfo(provider, flags,
@@ -5938,7 +5960,7 @@
final int userId = processName != null ? UserHandle.getUserId(uid)
: UserHandle.getCallingUserId();
if (!sUserManager.exists(userId)) return null;
- flags = augmentFlagsForUser(flags, userId);
+ flags = updateFlagsForComponent(flags, userId, processName);
ArrayList<ProviderInfo> finalList = null;
// reader
@@ -5951,7 +5973,7 @@
&& (processName == null
|| (p.info.processName.equals(processName)
&& UserHandle.isSameApp(p.info.applicationInfo.uid, uid)))
- && mSettings.isEnabledAndVisibleLPr(p.info, flags, userId)
+ && mSettings.isEnabledAndMatchLPr(p.info, flags, userId)
&& (!mSafeMode
|| (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) {
if (finalList == null) {
@@ -5975,8 +5997,7 @@
}
@Override
- public InstrumentationInfo getInstrumentationInfo(ComponentName name,
- int flags) {
+ public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
// reader
synchronized (mPackages) {
final PackageParser.Instrumentation i = mInstrumentation.get(name);
@@ -6171,7 +6192,6 @@
try {
pp.collectCertificates(pkg, parseFlags);
- pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
@@ -6259,7 +6279,7 @@
+ " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
if (!updatedPkg.codePath.equals(scanFile)) {
- Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : "
+ Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
+ ps.name + " changing from " + updatedPkg.codePathString
+ " to " + scanFile);
updatedPkg.codePath = scanFile;
@@ -6384,7 +6404,7 @@
baseResourcePath = ps.resourcePathString;
} else {
// Should not happen at all. Just log an error.
- Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName);
+ Slog.e(TAG, "Resource path not set for package " + pkg.packageName);
}
} else {
resourcePath = pkg.codePath;
@@ -6633,7 +6653,7 @@
synchronized (mPackages) {
pkg = mPackages.get(packageName);
if (pkg == null) {
- throw new IllegalArgumentException("Missing package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
}
@@ -7143,7 +7163,7 @@
pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Signature mismatch for shared user : "
+ "Signature mismatch for shared user: "
+ pkgSetting.sharedUser);
}
}
@@ -7395,7 +7415,7 @@
if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) {
if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) {
Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride +
- " for package: " + pkg.packageName);
+ " for package " + pkg.packageName);
}
}
@@ -8102,7 +8122,7 @@
ps.primaryCpuAbiString = adjustedAbi;
if (ps.pkg != null && ps.pkg.applicationInfo != null) {
ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
- Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
+ Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi);
mInstaller.rmdex(ps.codePathString,
getDexCodeInstructionSet(getPreferredInstructionSet()));
}
@@ -8340,7 +8360,7 @@
// 64 bit apps will see a 64 bit primary ABI,
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) {
- Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch.");
+ Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch.");
}
if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) {
@@ -9217,7 +9237,7 @@
protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
int match, int userId) {
if (!sUserManager.exists(userId)) return null;
- if (!mSettings.isEnabledAndVisibleLPr(info.activity.info, mFlags, userId)) {
+ if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {
return null;
}
final PackageParser.Activity activity = info.activity;
@@ -9441,7 +9461,7 @@
int match, int userId) {
if (!sUserManager.exists(userId)) return null;
final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter;
- if (!mSettings.isEnabledAndVisibleLPr(info.service.info, mFlags, userId)) {
+ if (!mSettings.isEnabledAndMatchLPr(info.service.info, mFlags, userId)) {
return null;
}
final PackageParser.Service service = info.service;
@@ -9664,7 +9684,7 @@
if (!sUserManager.exists(userId))
return null;
final PackageParser.ProviderIntentInfo info = filter;
- if (!mSettings.isEnabledAndVisibleLPr(info.provider.info, mFlags, userId)) {
+ if (!mSettings.isEnabledAndMatchLPr(info.provider.info, mFlags, userId)) {
return null;
}
final PackageParser.Provider provider = info.provider;
@@ -9737,23 +9757,24 @@
}
private static final class EphemeralIntentResolver
- extends IntentResolver<IntentFilter, ResolveInfo> {
+ extends IntentResolver<EphemeralResolveIntentInfo, EphemeralResolveInfo> {
@Override
- protected IntentFilter[] newArray(int size) {
- return new IntentFilter[size];
+ protected EphemeralResolveIntentInfo[] newArray(int size) {
+ return new EphemeralResolveIntentInfo[size];
}
@Override
- protected boolean isPackageForFilter(String packageName, IntentFilter info) {
+ protected boolean isPackageForFilter(String packageName, EphemeralResolveIntentInfo info) {
return true;
}
@Override
- protected ResolveInfo newResult(IntentFilter info, int match, int userId) {
- if (!sUserManager.exists(userId)) return null;
- final ResolveInfo res = new ResolveInfo();
- res.filter = info;
- return res;
+ protected EphemeralResolveInfo newResult(EphemeralResolveIntentInfo info, int match,
+ int userId) {
+ if (!sUserManager.exists(userId)) {
+ return null;
+ }
+ return info.getEphemeralResolveInfo();
}
}
@@ -10002,7 +10023,7 @@
}
final VerificationParams verifParams = new VerificationParams(
null, sessionParams.originatingUri, sessionParams.referrerUri,
- sessionParams.originatingUid, null);
+ sessionParams.originatingUid);
verifParams.setInstallerUid(installerUid);
final OriginInfo origin;
@@ -10191,6 +10212,36 @@
}
@Override
+ public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
+ "setPackageSuspended for user " + userId);
+
+ long callingId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting != null) {
+ if (pkgSetting.getSuspended(userId) != suspended) {
+ pkgSetting.setSuspended(suspended, userId);
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+
+ // TODO:
+ // * broadcast a PACKAGE_(UN)SUSPENDED intent for launchers to pick up
+ // * remove app from recents (kill app it if it is running)
+ // * erase existing notifications for this app
+ return true;
+ }
+
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
+ }
+
+ @Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
@@ -10387,10 +10438,6 @@
if (!DEFAULT_VERIFY_ENABLE) {
return false;
}
- // TODO: fix b/25118622; don't bypass verification
- if (Build.IS_DEBUGGABLE && (installFlags & PackageManager.INSTALL_QUICK) != 0) {
- return false;
- }
// Ephemeral apps don't get the full verification treatment
if ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0) {
if (DEBUG_EPHEMERAL) {
@@ -10559,7 +10606,7 @@
throw new SecurityException("Bad object " + obj + " for uid " + uid);
}
} else {
- throw new SecurityException("Unknown calling uid " + uid);
+ throw new SecurityException("Unknown calling UID: " + uid);
}
// Verify: can't set installerPackageName to a package that is
@@ -10958,13 +11005,6 @@
+ " file=" + origin.file + " cid=" + origin.cid + "}";
}
- public ManifestDigest getManifestDigest() {
- if (verificationParams == null) {
- return null;
- }
- return verificationParams.getManifestDigest();
- }
-
private int installLocationPolicy(PackageInfoLite pkgLite) {
String packageName = pkgLite.packageName;
int installLocation = pkgLite.installLocation;
@@ -11167,9 +11207,9 @@
PACKAGE_MIME_TYPE);
verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ // Query all live verifiers based on current user state
final List<ResolveInfo> receivers = queryIntentReceivers(verification,
- PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
- verifierUser.getIdentifier());
+ PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier());
if (DEBUG_VERIFY) {
Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -11383,7 +11423,6 @@
final int installFlags;
final String installerPackageName;
final String volumeUuid;
- final ManifestDigest manifestDigest;
final UserHandle user;
final String abiOverride;
final String[] installGrantPermissions;
@@ -11398,7 +11437,7 @@
InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, String volumeUuid,
- ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+ UserHandle user, String[] instructionSets,
String abiOverride, String[] installGrantPermissions,
String traceMethod, int traceCookie) {
this.origin = origin;
@@ -11407,7 +11446,6 @@
this.observer = observer;
this.installerPackageName = installerPackageName;
this.volumeUuid = volumeUuid;
- this.manifestDigest = manifestDigest;
this.user = user;
this.instructionSets = instructionSets;
this.abiOverride = abiOverride;
@@ -11482,8 +11520,8 @@
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location " + codePath + ", retcode=" + retCode);
+ Slog.w(TAG, "Couldn't remove dex file for package at location " + codePath
+ + ", retcode=" + retCode);
// we don't consider this to be a failure of the core package deletion
}
}
@@ -11509,7 +11547,7 @@
/** New install */
FileInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -11520,7 +11558,7 @@
/** Existing install */
FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
- super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+ super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
null, null, null, 0);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -11747,7 +11785,7 @@
/** New install */
AsecInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -11757,7 +11795,7 @@
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
// Hackily pretend we're still looking at a full code path
if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -11774,7 +11812,7 @@
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
- | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+ | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
instructionSets, null, null, null, 0);
this.cid = cid;
setMountPath(PackageHelper.getSdDir(cid));
@@ -12041,7 +12079,7 @@
/** New install */
MoveInstallArgs(InstallParams params) {
super(params.origin, params.move, params.observer, params.installFlags,
- params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.installerPackageName, params.volumeUuid,
params.getUser(), null /* instruction sets */, params.packageAbiOverride,
params.grantedRuntimePermissions,
params.traceMethod, params.traceCookie);
@@ -12517,7 +12555,7 @@
if((oldPkg == null) || (oldPkg.applicationInfo == null) ||
(oldPkgSetting == null)) {
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
- "Couldn't find package:" + packageName + " information");
+ "Couldn't find package " + packageName + " information");
return;
}
}
@@ -12753,7 +12791,6 @@
final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
|| (args.volumeUuid != null));
- final boolean quickInstall = ((installFlags & PackageManager.INSTALL_QUICK) != 0);
final boolean ephemeral = ((installFlags & PackageManager.INSTALL_EPHEMERAL) != 0);
boolean replace = false;
int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
@@ -12779,7 +12816,6 @@
| PackageParser.PARSE_ENFORCE_CODE
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
| (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
- | (quickInstall ? PackageParser.PARSE_SKIP_VERIFICATION : 0)
| (ephemeral ? PackageParser.PARSE_IS_EPHEMERAL : 0);
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
@@ -12817,35 +12853,6 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- /* If the installer passed in a manifest digest, compare it now. */
- if (args.manifestDigest != null) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectManifestDigest");
- try {
- pp.collectManifestDigest(pkg);
- } catch (PackageParserException e) {
- res.setError("Failed collect during installPackageLI", e);
- return;
- } finally {
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
-
- if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null ? "null"
- : pkg.manifestDigest.toString();
- Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
- + parsedManifest);
- }
-
- if (!args.manifestDigest.equals(pkg.manifestDigest)) {
- res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
- return;
- }
- } else if (DEBUG_INSTALL) {
- final String parsedManifest = pkg.manifestDigest == null
- ? "null" : pkg.manifestDigest.toString();
- Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
- }
-
// Get rid of all references to package scan path via parser.
pp = null;
String oldCodePath = null;
@@ -13633,7 +13640,7 @@
try {
newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
+ Slog.w(TAG, "Failed to restore system package " + newPs.name + ": " + e.getMessage());
return false;
}
@@ -13727,6 +13734,29 @@
}
}
+ @Override
+ public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
+ throw new SecurityException(
+ "setRequiredForSystemUser can only be run by the system or root");
+ }
+ synchronized (mPackages) {
+ PackageSetting ps = mSettings.mPackages.get(packageName);
+ if (ps == null) {
+ Log.w(TAG, "Package doesn't exist: " + packageName);
+ return false;
+ }
+ if (systemUserApp) {
+ ps.pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
+ } else {
+ ps.pkgPrivateFlags &= ~ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER;
+ }
+ mSettings.writeLPr();
+ }
+ return true;
+ }
+
/*
* This method handles package deletion in general
*/
@@ -13764,6 +13794,7 @@
true, //stopped
true, //notLaunched
false, //hidden
+ false, //suspended
null, null, null,
false, // blockUninstall
ps.readUserState(userId).domainVerificationStatus, 0);
@@ -13827,13 +13858,13 @@
boolean ret = false;
if (isSystemApp(ps)) {
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
+ if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled,
flags, outInfo, writeSettings);
} else {
- if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name);
+ if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
// Kill application pre-emptively especially for apps on sd.
killApplication(packageName, ps.appId, "uninstall pkg");
ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags,
@@ -13982,7 +14013,7 @@
// resorting to a full data wipe.
int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: " + packageName);
+ Slog.w(TAG, "Couldn't remove cache files for package " + packageName);
return false;
}
@@ -14212,7 +14243,7 @@
}
int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId);
if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
+ Slog.w(TAG, "Couldn't remove cache files for package "
+ packageName + " u" + userId);
return false;
}
@@ -14657,7 +14688,7 @@
}
synchronized (mPackages) {
Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
- " :");
+ ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
@@ -15062,12 +15093,10 @@
pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
if (className == null) {
- throw new IllegalArgumentException(
- "Unknown package: " + packageName);
+ throw new IllegalArgumentException("Unknown package: " + packageName);
}
throw new IllegalArgumentException(
- "Unknown component: " + packageName
- + "/" + className);
+ "Unknown component: " + packageName + "/" + className);
}
// Allow root and verify that userId is not being specified by a different user
if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {
@@ -17109,7 +17138,7 @@
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -17125,7 +17154,7 @@
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
if (pkg.applicationInfo.uid != Binder.getCallingUid()
@@ -17145,7 +17174,7 @@
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
IBinder ksh = ks.getToken();
@@ -17165,7 +17194,7 @@
synchronized(mPackages) {
final PackageParser.Package pkg = mPackages.get(packageName);
if (pkg == null) {
- Slog.w(TAG, "KeySet requested for unknown package:" + packageName);
+ Slog.w(TAG, "KeySet requested for unknown package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
IBinder ksh = ks.getToken();
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index b18c846..901749e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -46,7 +46,6 @@
import android.os.ShellCommand;
import android.os.UserHandle;
import android.text.TextUtils;
-
import android.util.PrintWriterPrinter;
import com.android.internal.util.SizedInputStream;
@@ -109,6 +108,10 @@
return runQueryIntentServices();
case "query-receivers":
return runQueryIntentReceivers();
+ case "suspend":
+ return runSuspend(true);
+ case "unsuspend":
+ return runSuspend(false);
default:
return handleDefaultCommands(cmd);
}
@@ -123,29 +126,76 @@
final InstallParams params = makeInstallParams();
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
+ boolean abandonSession = true;
+ try {
+ final String inPath = getNextArg();
+ if (inPath == null && params.sessionParams.sizeBytes == 0) {
+ pw.println("Error: must either specify a package size or an APK file");
+ return 1;
+ }
+ if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
+ false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ if (doCommitSession(sessionId, false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
+ return 1;
+ }
+ abandonSession = false;
+ pw.println("Success");
+ return 0;
+ } finally {
+ if (abandonSession) {
+ try {
+ doAbandonSession(sessionId, false /*logSuccess*/);
+ } catch (Exception ignore) {
+ }
+ }
+ }
+ }
- final String inPath = getNextArg();
- if (inPath == null && params.sessionParams.sizeBytes == 0) {
- pw.println("Error: must either specify a package size or an APK file");
+ private int runSuspend(boolean suspendedState) {
+ final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ String packageName = getNextArg();
+ if (packageName == null) {
+ pw.println("Error: package name not specified");
return 1;
}
- if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk") != 0) {
+
+ try {
+ mInterface.setPackageSuspendedAsUser(packageName, suspendedState, userId);
+ ApplicationInfo appInfo = mInterface.getApplicationInfo(
+ packageName, 0, userId);
+
+ pw.println("Package " + packageName + " new suspended state: "
+ + ((appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0));
+ return 0;
+ } catch (RemoteException e) {
+ pw.println(e.toString());
return 1;
}
- if (doCommitSession(sessionId) != 0) {
- return 1;
- }
- return 0;
}
private int runInstallAbandon() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
- return doAbandonSession(sessionId);
+ return doAbandonSession(sessionId, true /*logSuccess*/);
}
private int runInstallCommit() throws RemoteException {
final int sessionId = Integer.parseInt(getNextArg());
- return doCommitSession(sessionId);
+ return doCommitSession(sessionId, true /*logSuccess*/);
}
private int runInstallCreate() throws RemoteException {
@@ -174,7 +224,7 @@
final int sessionId = Integer.parseInt(getNextArg());
final String splitName = getNextArg();
final String path = getNextArg();
- return doWriteSession(sessionId, path, sizeBytes, splitName);
+ return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
}
private int runList() throws RemoteException {
@@ -520,7 +570,7 @@
} else {
final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId);
if (info == null) {
- pw.println("Failure - not installed for " + userId);
+ pw.println("Failure [not installed for " + userId + "]");
return 1;
}
final boolean isSystem =
@@ -789,8 +839,8 @@
return sessionId;
}
- private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName)
- throws RemoteException {
+ private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
+ boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
if ("-".equals(inPath)) {
inPath = null;
@@ -831,7 +881,9 @@
}
session.fsync(out);
- pw.println("Success: streamed " + total + " bytes");
+ if (logSuccess) {
+ pw.println("Success: streamed " + total + " bytes");
+ }
return 0;
} catch (IOException e) {
pw.println("Error: failed to write; " + e.getMessage());
@@ -843,7 +895,7 @@
}
}
- private int doCommitSession(int sessionId) throws RemoteException {
+ private int doCommitSession(int sessionId, boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
@@ -857,11 +909,12 @@
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) {
- pw.println("Success");
+ if (logSuccess) {
+ System.out.println("Success");
+ }
} else {
pw.println("Failure ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
- pw.println("Failure details: " + result.getExtras());
}
return status;
} finally {
@@ -869,14 +922,16 @@
}
}
- private int doAbandonSession(int sessionId) throws RemoteException {
+ private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
PackageInstaller.Session session = null;
try {
session = new PackageInstaller.Session(
mInterface.getPackageInstaller().openSession(sessionId));
session.abandon();
- pw.println("Success");
+ if (logSuccess) {
+ pw.println("Success");
+ }
return 0;
} finally {
IoUtils.closeQuietly(session);
@@ -1017,7 +1072,7 @@
pw.println(" list features");
pw.println(" Prints all features of the system.");
pw.println(" list instrumentation [-f] [TARGET-PACKAGE]");
- pw.println(" Prints all test packages; optionally only those targetting TARGET-PACKAGE");
+ pw.println(" Prints all test packages; optionally only those targeting TARGET-PACKAGE");
pw.println(" Options:");
pw.println(" -f: dump the name of the .apk file containing the test package");
pw.println(" list libraries");
@@ -1051,6 +1106,10 @@
pw.println(" Prints all services that can handle the given Intent.");
pw.println(" query-receivers [--user USER_ID] INTENT");
pw.println(" Prints all broadcast receivers that can handle the given Intent.");
+ pw.println(" suspend [--user USER_ID] TARGET-PACKAGE");
+ pw.println(" Suspends the specified package (as user).");
+ pw.println(" unsuspend [--user USER_ID] TARGET-PACKAGE");
+ pw.println(" Unsuspends the specified package (as user).");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 78328f5..1117988 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -332,6 +332,14 @@
modifyUserState(userId).hidden = hidden;
}
+ boolean getSuspended(int userId) {
+ return readUserState(userId).suspended;
+ }
+
+ void setSuspended(boolean suspended, int userId) {
+ modifyUserState(userId).suspended = suspended;
+ }
+
boolean getBlockUninstall(int userId) {
return readUserState(userId).blockUninstall;
}
@@ -341,7 +349,7 @@
}
void setUserState(int userId, int enabled, boolean installed, boolean stopped,
- boolean notLaunched, boolean hidden,
+ boolean notLaunched, boolean hidden, boolean suspended,
String lastDisableAppCaller, ArraySet<String> enabledComponents,
ArraySet<String> disabledComponents, boolean blockUninstall, int domainVerifState,
int linkGeneration) {
@@ -351,6 +359,7 @@
state.stopped = stopped;
state.notLaunched = notLaunched;
state.hidden = hidden;
+ state.suspended = suspended;
state.lastDisableAppCaller = lastDisableAppCaller;
state.enabledComponents = enabledComponents;
state.disabledComponents = disabledComponents;
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 5cf92a9..2921032 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -49,6 +49,7 @@
void setPrivateFlags(int pkgPrivateFlags) {
this.pkgPrivateFlags = pkgPrivateFlags
& (ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
- | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK);
+ | ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK
+ | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 22f8e96..3f9ce7a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -16,23 +16,42 @@
package com.android.server.pm;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
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.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.os.Process.SYSTEM_UID;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.os.Process.PACKAGE_INFO_GID;
+import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION;
import android.annotation.NonNull;
+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.ComponentInfo;
import android.content.pm.IntentFilterVerificationInfo;
+import android.content.pm.PackageCleanItem;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageUserState;
+import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.pm.VerifierDeviceIdentity;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -47,11 +66,18 @@
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
-import android.util.AtomicFile;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.Log;
import android.util.LogPrinter;
+import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.SparseLongArray;
+import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
@@ -65,53 +91,37 @@
import com.android.server.pm.PackageManagerService.DumpState;
import com.android.server.pm.PermissionsState.PermissionState;
-import java.io.FileNotFoundException;
-import java.util.Collection;
+import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ComponentInfo;
-import android.content.pm.PackageCleanItem;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
-import android.content.pm.PermissionInfo;
-import android.content.pm.Signature;
-import android.content.pm.UserInfo;
-import android.content.pm.PackageUserState;
-import android.content.pm.VerifierDeviceIdentity;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.Xml;
-
+import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
import java.io.PrintWriter;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.Map.Entry;
-
-import libcore.io.IoUtils;
/**
* Holds information about dynamic settings.
@@ -195,6 +205,7 @@
private static final String ATTR_BLOCKED = "blocked";
// New name for the above attribute.
private static final String ATTR_HIDDEN = "hidden";
+ private static final String ATTR_SUSPENDED = "suspended";
private static final String ATTR_INSTALLED = "inst";
private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
@@ -420,7 +431,7 @@
boolean disableSystemPackageLPw(String name) {
final PackageSetting p = mPackages.get(name);
if(p == null) {
- Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package");
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not an installed package");
return false;
}
final PackageSetting dp = mDisabledSysPackages.get(name);
@@ -445,7 +456,7 @@
PackageSetting enableSystemPackageLPw(String name) {
PackageSetting p = mDisabledSysPackages.get(name);
if(p == null) {
- Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled");
+ Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled");
return null;
}
// Reset flag in ApplicationInfo object
@@ -661,6 +672,7 @@
true, // stopped,
true, // notLaunched
false, // hidden
+ false, // suspended
null, null, null,
false, // blockUninstall
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
@@ -1331,7 +1343,7 @@
throws XmlPullParserException, IOException {
IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser);
packageSetting.setIntentFilterVerificationInfo(ivi);
- Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
+ Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName());
}
private void readRestoredIntentFilterVerifications(XmlPullParser parser)
@@ -1423,6 +1435,7 @@
false, // stopped
false, // notLaunched
false, // hidden
+ false, // suspended
null, null, null,
false, // blockUninstall
INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0);
@@ -1464,7 +1477,7 @@
String name = parser.getAttributeValue(null, ATTR_NAME);
ps = mPackages.get(name);
if (ps == null) {
- Slog.w(PackageManagerService.TAG, "No package known for stopped package: "
+ Slog.w(PackageManagerService.TAG, "No package known for stopped package "
+ name);
XmlUtils.skipCurrentTag(parser);
continue;
@@ -1488,6 +1501,9 @@
final String hiddenStr = parser.getAttributeValue(null, ATTR_HIDDEN);
hidden = hiddenStr == null
? hidden : Boolean.parseBoolean(hiddenStr);
+ final String suspendedStr = parser.getAttributeValue(null, ATTR_SUSPENDED);
+ final boolean suspended = suspendedStr == null
+ ? false : Boolean.parseBoolean(suspendedStr);
final String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED);
final boolean notLaunched = stoppedStr == null
? false : Boolean.parseBoolean(notLaunchedStr);
@@ -1528,8 +1544,8 @@
}
ps.setUserState(userId, enabled, installed, stopped, notLaunched, hidden,
- enabledCaller, enabledComponents, disabledComponents, blockUninstall,
- verifState, linkGeneration);
+ suspended, enabledCaller, enabledComponents, disabledComponents,
+ blockUninstall, verifState, linkGeneration);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
@@ -1763,6 +1779,7 @@
if (ustate.stopped || ustate.notLaunched || !ustate.installed
|| ustate.enabled != COMPONENT_ENABLED_STATE_DEFAULT
|| ustate.hidden
+ || ustate.suspended
|| (ustate.enabledComponents != null
&& ustate.enabledComponents.size() > 0)
|| (ustate.disabledComponents != null
@@ -1786,6 +1803,9 @@
if (ustate.hidden) {
serializer.attribute(null, ATTR_HIDDEN, "true");
}
+ if (ustate.suspended) {
+ serializer.attribute(null, ATTR_SUSPENDED, "true");
+ }
if (ustate.blockUninstall) {
serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
}
@@ -2021,7 +2041,7 @@
}
} else {
Slog.w(PackageManagerService.TAG,
- "No package known for stopped package: " + name);
+ "No package known for stopped package " + name);
}
XmlUtils.skipCurrentTag(parser);
} else {
@@ -2239,11 +2259,11 @@
JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
final File writeTarget = journal.chooseForWrite();
- FileOutputStream fstr = null;
- BufferedOutputStream str = null;
+ FileOutputStream fstr;
+ BufferedWriter writer = null;
try {
fstr = new FileOutputStream(writeTarget);
- str = new BufferedOutputStream(fstr);
+ writer = new BufferedWriter(new OutputStreamWriter(fstr, Charset.defaultCharset()));
FileUtils.setPermissions(fstr.getFD(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
StringBuilder sb = new StringBuilder();
@@ -2260,7 +2280,7 @@
final int[] gids = pkg.getPermissionsState().computeGids(userIds);
// Avoid any application that has a space in its path.
- if (dataPath.indexOf(" ") >= 0)
+ if (dataPath.indexOf(' ') >= 0)
continue;
// we store on each line the following information for now:
@@ -2282,7 +2302,7 @@
sb.setLength(0);
sb.append(ai.packageName);
sb.append(" ");
- sb.append((int)ai.uid);
+ sb.append(ai.uid);
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append(" ");
@@ -2298,15 +2318,15 @@
sb.append("none");
}
sb.append("\n");
- str.write(sb.toString().getBytes());
+ writer.append(sb);
}
- str.flush();
+ writer.flush();
FileUtils.sync(fstr);
- str.close();
+ writer.close();
journal.commit();
} catch (Exception e) {
Slog.wtf(TAG, "Failed to write packages.list", e);
- IoUtils.closeQuietly(str);
+ IoUtils.closeQuietly(writer);
journal.rollback();
}
}
@@ -2789,9 +2809,9 @@
}
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
- FileInputStream str = null;
+ InputStream str = null;
try {
- str = new FileInputStream(f);
+ str = new BufferedInputStream(new FileInputStream(f));
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, null);
@@ -2842,7 +2862,7 @@
for (int i=0; i<tmpPa.countCategories(); i++) {
String cat = tmpPa.getCategory(i);
if (cat.equals(Intent.CATEGORY_DEFAULT)) {
- flags |= PackageManager.MATCH_DEFAULT_ONLY;
+ flags |= MATCH_DEFAULT_ONLY;
} else {
intent.addCategory(cat);
}
@@ -2992,7 +3012,7 @@
filter.addCategory(cat);
}
}
- if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) {
+ if ((flags & MATCH_DEFAULT_ONLY) != 0) {
filter.addCategory(Intent.CATEGORY_DEFAULT);
}
if (scheme != null) {
@@ -3778,17 +3798,16 @@
return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
}
- boolean isEnabledAndVisibleLPr(ComponentInfo componentInfo, int flags, int userId) {
+ boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
return isEnabledLPr(componentInfo, flags, userId)
- && isVisibleLPr(componentInfo, flags);
+ && isMatchLPr(componentInfo, flags);
}
private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) {
- if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) {
+ if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
return true;
}
- final String pkgName = componentInfo.packageName;
- final PackageSetting packageSettings = mPackages.get(pkgName);
+ final PackageSetting packageSettings = mPackages.get(componentInfo.packageName);
if (PackageManagerService.DEBUG_SETTINGS) {
Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = "
+ componentInfo.packageName + " componentName = " + componentInfo.name);
@@ -3801,7 +3820,7 @@
return false;
}
PackageUserState ustate = packageSettings.readUserState(userId);
- if ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
+ if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) {
if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
return true;
}
@@ -3824,14 +3843,19 @@
return componentInfo.enabled;
}
- private boolean isVisibleLPr(ComponentInfo componentInfo, int flags) {
- if ((flags & PackageManager.GET_ENCRYPTION_UNAWARE_COMPONENTS) != 0) {
- return true;
+ private boolean isMatchLPr(ComponentInfo componentInfo, int flags) {
+ if ((flags & MATCH_SYSTEM_ONLY) != 0) {
+ final PackageSetting ps = mPackages.get(componentInfo.packageName);
+ if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ return false;
+ }
}
- if ((flags & PackageManager.MATCH_ENCRYPTION_AWARE_ONLY) != 0) {
- return componentInfo.encryptionAware;
- }
- return true;
+
+ final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
+ && !componentInfo.encryptionAware;
+ final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
+ && componentInfo.encryptionAware;
+ return matchesUnaware || matchesAware;
}
String getInstallerPackageNameLPr(String packageName) {
@@ -4022,6 +4046,7 @@
pw.print(",");
pw.print(ps.getInstalled(user.id) ? "I" : "i");
pw.print(ps.getHidden(user.id) ? "B" : "b");
+ pw.print(ps.getSuspended(user.id) ? "SU" : "su");
pw.print(ps.getStopped(user.id) ? "S" : "s");
pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
pw.print(",");
@@ -4221,6 +4246,8 @@
pw.print(ps.getInstalled(user.id));
pw.print(" hidden=");
pw.print(ps.getHidden(user.id));
+ pw.print(" suspended=");
+ pw.print(ps.getSuspended(user.id));
pw.print(" stopped=");
pw.print(ps.getStopped(user.id));
pw.print(" notLaunched=");
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0b59c16..3d614a3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -69,6 +69,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
@@ -166,6 +167,10 @@
private static final String XATTR_SERIAL = "user.serial";
+ // Tron counters
+ private static final String TRON_GUEST_CREATED = "users_guest_created";
+ private static final String TRON_USER_CREATED = "users_user_created";
+
private final Context mContext;
private final PackageManagerService mPm;
private final Object mPackagesLock;
@@ -526,6 +531,7 @@
if (parentHandle != null) {
intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
intent.putExtra(Intent.EXTRA_USER, profileHandle);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtras(extras);
mContext.sendBroadcastAsUser(intent, parentHandle);
@@ -1123,7 +1129,7 @@
*/
private static final void checkManageUsersPermission(String message) {
final int uid = Binder.getCallingUid();
- if (uid != Process.SYSTEM_UID && uid != 0
+ if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID
&& ActivityManager.checkComponentPermission(
android.Manifest.permission.MANAGE_USERS,
uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
@@ -1131,6 +1137,20 @@
}
}
+ /**
+ * Enforces that only the system UID or root's UID (on any user) can make certain calls to the
+ * UserManager.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ private static void checkSystemOrRoot(String message) {
+ final int uid = Binder.getCallingUid();
+ if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+ throw new SecurityException("Only system may: " + message);
+ }
+ }
+
private void writeBitmapLP(UserInfo info, Bitmap bitmap) {
try {
File dir = new File(mUsersDir, Integer.toString(info.id));
@@ -1815,6 +1835,7 @@
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS);
+ MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -2059,6 +2080,7 @@
managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
Intent.FLAG_RECEIVER_FOREGROUND);
managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
+ managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId);
mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
}
@@ -2071,7 +2093,7 @@
public Bundle getApplicationRestrictionsForUser(String packageName, int userId) {
if (UserHandle.getCallingUserId() != userId
|| !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
- checkManageUsersPermission("get application restrictions for other users/apps");
+ checkSystemOrRoot("get application restrictions for other users/apps");
}
synchronized (mPackagesLock) {
// Read the restrictions from XML
@@ -2082,7 +2104,7 @@
@Override
public void setApplicationRestrictions(String packageName, Bundle restrictions,
int userId) {
- checkManageUsersPermission("set application restrictions");
+ checkSystemOrRoot("set application restrictions");
synchronized (mPackagesLock) {
if (restrictions == null || restrictions.isEmpty()) {
cleanAppRestrictionsForPackage(packageName, userId);
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index c8523c9..3eae7fc 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -278,7 +278,7 @@
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
if (Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) {
- mItems.add(getBugReportAction());
+ mItems.add(new BugReportAction());
}
} else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) {
if (mShowSilentToggle) {
@@ -367,60 +367,65 @@
}
}
- private Action getBugReportAction() {
- return new SinglePressAction(com.android.internal.R.drawable.ic_lock_bugreport,
- R.string.bugreport_title) {
+ private class BugReportAction extends SinglePressAction implements LongPressAction {
- public void onPress() {
- AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
- builder.setTitle(com.android.internal.R.string.bugreport_title);
- builder.setMessage(com.android.internal.R.string.bugreport_message);
- builder.setNegativeButton(com.android.internal.R.string.cancel, null);
- builder.setPositiveButton(com.android.internal.R.string.report,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // don't actually trigger the bugreport if we are running stability
- // tests via monkey
- if (ActivityManager.isUserAMonkey()) {
- return;
- }
- // Add a little delay before executing, to give the
- // dialog a chance to go away before it takes a
- // screenshot.
- mHandler.postDelayed(new Runnable() {
- @Override public void run() {
- // TODO: select 'progress' flag according to menu choice
- try {
- ActivityManagerNative.getDefault()
- .requestBugReport(true);
- } catch (RemoteException e) {
- }
- }
- }, 500);
- }
- });
- AlertDialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.show();
+ public BugReportAction() {
+ super(com.android.internal.R.drawable.ic_lock_bugreport, R.string.bugreport_title);
+ }
+
+ @Override
+ public void onPress() {
+ // don't actually trigger the bugreport if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
+ return;
}
+ // Add a little delay before executing, to give the
+ // dialog a chance to go away before it takes a
+ // screenshot.
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Take an "interactive" bugreport.
+ ActivityManagerNative.getDefault().requestBugReport(true);
+ } catch (RemoteException e) {
+ }
+ }
+ }, 500);
+ }
- public boolean showDuringKeyguard() {
- return true;
- }
-
- public boolean showBeforeProvisioning() {
+ @Override
+ public boolean onLongPress() {
+ // don't actually trigger the bugreport if we are running stability
+ // tests via monkey
+ if (ActivityManager.isUserAMonkey()) {
return false;
}
-
- @Override
- public String getStatus() {
- return mContext.getString(
- com.android.internal.R.string.bugreport_status,
- Build.VERSION.RELEASE,
- Build.ID);
+ try {
+ // Take a "full" bugreport.
+ ActivityManagerNative.getDefault().requestBugReport(false);
+ } catch (RemoteException e) {
}
- };
+ return false;
+ }
+
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+
+ @Override
+ public String getStatus() {
+ return mContext.getString(
+ com.android.internal.R.string.bugreport_status,
+ Build.VERSION.RELEASE,
+ Build.ID);
+ }
}
private Action getSettingsAction() {
@@ -742,13 +747,6 @@
mIcon = icon;
}
- protected SinglePressAction(int iconResId, CharSequence message) {
- mIconResId = iconResId;
- mMessageResId = 0;
- mMessage = message;
- mIcon = null;
- }
-
public boolean isEnabled() {
return true;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index dff6e3f..4fbc030 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2063,7 +2063,8 @@
attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
}
if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || mForceWindowDrawsStatusBarBackground) {
+ || (mForceWindowDrawsStatusBarBackground
+ && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT)) {
attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
}
}
@@ -2878,7 +2879,7 @@
} else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) {
if (down) {
if (repeatCount == 0) {
- showKeyboardShortcutsMenu();
+ toggleKeyboardShortcutsMenu();
}
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
@@ -3310,11 +3311,11 @@
}
}
- private void showKeyboardShortcutsMenu() {
+ private void toggleKeyboardShortcutsMenu() {
try {
IStatusBarService statusbar = getStatusBarService();
if (statusbar != null) {
- statusbar.showKeyboardShortcutsMenu();
+ statusbar.toggleKeyboardShortcutsMenu();
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e);
@@ -3380,7 +3381,6 @@
if (awakenFromDreams) {
awakenDreams();
}
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
hideRecentApps(false, true);
} else {
// Otherwise, just launch Home
@@ -4242,6 +4242,7 @@
&& (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
&& (attrs.type == TYPE_STATUS_BAR
|| attrs.type == TYPE_TOAST
+ || attrs.type == TYPE_DOCK_DIVIDER
|| attrs.type == TYPE_VOICE_INTERACTION_STARTING
|| (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
diff --git a/services/core/java/com/android/server/policy/ShortcutManager.java b/services/core/java/com/android/server/policy/ShortcutManager.java
index 76f56bc..9908624 100644
--- a/services/core/java/com/android/server/policy/ShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ShortcutManager.java
@@ -128,13 +128,15 @@
ActivityInfo info = null;
ComponentName componentName = new ComponentName(packageName, className);
try {
- info = packageManager.getActivityInfo(componentName, 0);
+ info = packageManager.getActivityInfo(componentName,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
} catch (PackageManager.NameNotFoundException e) {
String[] packages = packageManager.canonicalToCurrentPackageNames(
new String[] { packageName });
componentName = new ComponentName(packages[0], className);
try {
- info = packageManager.getActivityInfo(componentName, 0);
+ info = packageManager.getActivityInfo(componentName,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
} catch (PackageManager.NameNotFoundException e1) {
Log.w(TAG, "Unable to add bookmark: " + packageName
+ "/" + className, e);
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index c0dfbcb..549d2dc 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -126,6 +126,7 @@
final ComponentName keyguardComponent = ComponentName.unflattenFromString(
resources.getString(com.android.internal.R.string.config_keyguardComponent));
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
intent.setComponent(keyguardComponent);
if (!context.bindServiceAsUser(intent, mKeyguardConnection,
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index fc27170..2d38da5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -503,10 +503,10 @@
}
@Override
- public void showKeyboardShortcutsMenu() {
+ public void toggleKeyboardShortcutsMenu() {
if (mBar != null) {
try {
- mBar.showKeyboardShortcutsMenu();
+ mBar.toggleKeyboardShortcutsMenu();
} catch (RemoteException ex) {}
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4b6db99..d888c56 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -53,7 +53,6 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.storage.StorageManager;
import android.provider.Settings;
import android.service.trust.TrustAgentService;
import android.util.ArraySet;
@@ -681,7 +680,9 @@
public boolean isDeviceSecure(int userId) throws RemoteException {
userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
- userId = resolveProfileParent(userId);
+ if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+ userId = resolveProfileParent(userId);
+ }
long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 7f4c42b..578428b 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -17,6 +17,7 @@
package com.android.server.tv;
import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED;
+import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY;
import static android.media.tv.TvInputManager.INPUT_STATE_DISCONNECTED;
import android.content.BroadcastReceiver;
@@ -38,6 +39,7 @@
import android.media.AudioPatch;
import android.media.AudioPort;
import android.media.AudioPortConfig;
+import android.media.AudioSystem;
import android.media.tv.ITvInputHardware;
import android.media.tv.ITvInputHardwareCallback;
import android.media.tv.TvInputHardwareInfo;
@@ -102,7 +104,6 @@
private int mCurrentIndex = 0;
private int mCurrentMaxIndex = 0;
- // TODO: Should handle STANDBY case.
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
private final List<Message> mPendingHdmiDeviceEvents = new LinkedList<>();
@@ -206,7 +207,7 @@
String inputId = mHardwareInputIdMap.get(deviceId);
if (inputId != null) {
mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
- convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget();
+ obtainStateFromConfigs(configs), 0, inputId).sendToTarget();
}
ITvInputHardwareCallback callback = connection.getCallbackLocked();
if (callback != null) {
@@ -256,12 +257,13 @@
|| connectionCallingUid != callingUid || connectionResolvedUserId != resolvedUserId;
}
- private int convertConnectedToState(boolean connected) {
- if (connected) {
- return INPUT_STATE_CONNECTED;
- } else {
- return INPUT_STATE_DISCONNECTED;
+ private int obtainStateFromConfigs(TvStreamConfig[] configs) {
+ for (TvStreamConfig config : configs) {
+ if ((config.getFlags() & TvStreamConfig.FLAG_MASK_SIGNAL_DETECTION) != 0) {
+ return INPUT_STATE_CONNECTED;
+ }
}
+ return (configs.length > 0) ? INPUT_STATE_CONNECTED_STANDBY : INPUT_STATE_DISCONNECTED;
}
public void addHardwareTvInput(int deviceId, TvInputInfo info) {
@@ -286,9 +288,14 @@
}
String inputId = mHardwareInputIdMap.get(hardwareInfo.getDeviceId());
if (inputId != null && inputId.equals(info.getId())) {
- mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
- convertConnectedToState(mHdmiStateMap.valueAt(i)), 0,
- inputId).sendToTarget();
+ // No HDMI hotplug does not necessarily mean disconnected, as old devices may
+ // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to
+ // denote unknown state.
+ int state = mHdmiStateMap.valueAt(i)
+ ? INPUT_STATE_CONNECTED
+ : INPUT_STATE_CONNECTED_STANDBY;
+ mHandler.obtainMessage(
+ ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget();
return;
}
}
@@ -296,7 +303,7 @@
Connection connection = mConnections.get(deviceId);
if (connection != null) {
mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
- convertConnectedToState(connection.getConfigsLocked().length > 0), 0,
+ obtainStateFromConfigs(connection.getConfigsLocked()), 0,
info.getId()).sendToTarget();
}
}
@@ -697,7 +704,8 @@
}
int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
for (AudioDevicePort port : devicePorts) {
- if ((port.type() & sinkDevice) != 0) {
+ if ((port.type() & sinkDevice) != 0 &&
+ (port.type() & AudioSystem.DEVICE_BIT_IN) == 0) {
sinks.add(port);
}
}
@@ -1110,8 +1118,14 @@
if (inputId == null) {
return;
}
- mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
- convertConnectedToState(event.isConnected()), 0, inputId).sendToTarget();
+ // No HDMI hotplug does not necessarily mean disconnected, as old devices may
+ // not report hotplug state correctly. Using INPUT_STATE_CONNECTED_STANDBY to
+ // denote unknown state.
+ int state = event.isConnected()
+ ? INPUT_STATE_CONNECTED
+ : INPUT_STATE_CONNECTED_STANDBY;
+ mHandler.obtainMessage(
+ ListenerHandler.STATE_CHANGED, state, 0, inputId).sendToTarget();
}
}
}
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
new file mode 100644
index 0000000..42db364
--- /dev/null
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vr;
+
+/**
+ * VR mode local system service interface.
+ *
+ * @hide Only for use within system server.
+ */
+public abstract class VrManagerInternal {
+
+ /**
+ * Return current VR mode state.
+ *
+ * @return {@code true} if VR mode is enabled.
+ */
+ public abstract boolean isInVrMode();
+
+ /**
+ * Set the current VR mode state.
+ *
+ * @param enabled {@code true} to enable VR mode.
+ */
+ public abstract void setVrMode(boolean enabled);
+
+ /**
+ * Add a listener for VR mode state changes.
+ * <p>
+ * This listener will immediately be called with the current VR mode state.
+ * </p>
+ * @param listener the listener instance to add.
+ */
+ public abstract void registerListener(VrStateListener listener);
+
+ /**
+ * Remove the listener from the current set of listeners.
+ *
+ * @param listener the listener to remove.
+ */
+ public abstract void unregisterListener(VrStateListener listener);
+
+}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
new file mode 100644
index 0000000..9a55e7f
--- /dev/null
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.vr;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+
+/**
+ * Service tracking whether VR mode is active, and notifying listening system services of state
+ * changes.
+ *
+ * {@hide}
+ */
+public class VrManagerService extends SystemService {
+
+ public static final boolean DEBUG = false;
+ public static final String TAG = "VrManagerService";
+
+ private final Object mLock = new Object();
+ private boolean mVrModeEnabled = false;
+ private ArraySet<VrStateListener> mListeners = new ArraySet<>();
+
+ private final class LocalService extends VrManagerInternal {
+ @Override
+ public boolean isInVrMode() {
+ return VrManagerService.this.getVrMode();
+ }
+
+ @Override
+ public void setVrMode(boolean enabled) {
+ VrManagerService.this.setVrMode(enabled);
+ }
+
+ @Override
+ public void registerListener(VrStateListener listener) {
+ VrManagerService.this.addListener(listener);
+ }
+
+ @Override
+ public void unregisterListener(VrStateListener listener) {
+ VrManagerService.this.removeListener(listener);
+ }
+ }
+
+ public VrManagerService(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ publishLocalService(VrManagerInternal.class, new LocalService());
+ }
+
+ private void addListener(VrStateListener listener) {
+ synchronized (mLock) {
+ mListeners.add(listener);
+ }
+ }
+
+ private void removeListener(VrStateListener listener) {
+ synchronized (mLock) {
+ mListeners.remove(listener);
+ }
+ }
+
+ private void setVrMode(boolean enabled) {
+ synchronized (mLock) {
+ if (mVrModeEnabled != enabled) {
+ mVrModeEnabled = enabled;
+ if (DEBUG) Slog.d(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
+ onVrModeChangedLocked();
+ }
+ }
+ }
+
+ private boolean getVrMode() {
+ synchronized (mLock) {
+ return mVrModeEnabled;
+ }
+ }
+
+ /**
+ * Notify system services of VR mode change.
+ */
+ private void onVrModeChangedLocked() {
+ for (VrStateListener l : mListeners) {
+ l.onVrStateChanged(mVrModeEnabled);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java b/services/core/java/com/android/server/vr/VrStateListener.java
similarity index 63%
copy from packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
copy to services/core/java/com/android/server/vr/VrStateListener.java
index e0d83fd..b8af4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
+++ b/services/core/java/com/android/server/vr/VrStateListener.java
@@ -13,20 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.systemui.recents.events.ui;
-
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.model.Task;
+package com.android.server.vr;
/**
- * This is sent when a {@link Task} is resized.
+ * Listener for state changes in VrManagerService,
*/
-public class ResizeTaskEvent extends EventBus.Event {
+public abstract class VrStateListener {
- public final Task task;
-
- public ResizeTaskEvent(Task task) {
- this.task = task;
- }
+ /**
+ * Called when the VR mode state changes.
+ *
+ * @param enabled {@code true} if VR mode is enabled.
+ */
+ public abstract void onVrStateChanged(boolean enabled);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index ab47f07..8292997 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -223,7 +223,7 @@
}
if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + winAnimator.mAnimLayer);
if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
- mService.setInputMethodAnimLayerAdjustment(adj);
+ mService.mLayersController.setInputMethodAnimLayerAdjustment(adj);
}
wallpaperController.setAnimLayerAdjustment(w, adj);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b49641f..751f871 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.ActivityManager.StackId;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -24,12 +25,14 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION;
import com.android.server.input.InputApplicationHandle;
import com.android.server.wm.WindowManagerService.H;
import android.annotation.NonNull;
import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
import android.os.Message;
import android.os.RemoteException;
import android.util.Slog;
@@ -38,6 +41,7 @@
import android.view.WindowManager;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
class AppTokenList extends ArrayList<AppWindowToken> {
@@ -123,6 +127,10 @@
// True if the windows associated with this token should be cropped to their stack bounds.
boolean mCropWindowsToStack;
+ boolean mAlwaysFocusable;
+
+ ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
+
AppWindowToken(WindowManagerService _service, IApplicationToken _token,
boolean _voiceInteraction) {
super(_service, _token.asBinder(),
@@ -256,8 +264,8 @@
return candidate;
}
- boolean stackCanReceiveKeys() {
- return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+ boolean windowsAreFocusable() {
+ return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
}
boolean isVisible() {
@@ -396,12 +404,28 @@
}
}
+ void resetReplacingWindows() {
+ if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken
+ + " of replacing window marks.");
+
+ for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+ final WindowState w = allAppWindows.get(i);
+ w.resetReplacing();
+ }
+ }
+
void addWindow(WindowState w) {
for (int i = allAppWindows.size() - 1; i >= 0; i--) {
WindowState candidate = allAppWindows.get(i);
if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
candidate.getWindowTag().equals(w.getWindowTag().toString())) {
candidate.mReplacingWindow = w;
+
+ // if we got a replacement window, reset the timeout to give drawing more time
+ service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+ service.mH.sendMessageDelayed(
+ service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this),
+ WINDOW_REPLACEMENT_TIMEOUT_DURATION);
}
}
allAppWindows.add(w);
@@ -417,7 +441,7 @@
return false;
}
- void clearTimedoutReplaceesLocked() {
+ void clearTimedoutReplacesLocked() {
for (int i = allAppWindows.size() - 1; i >= 0;
// removeWindowLocked at bottom of loop may remove multiple entries from
// allAppWindows if the window to be removed has child windows. It also may
@@ -430,10 +454,31 @@
continue;
}
candidate.mWillReplaceWindow = false;
- service.removeWindowLocked(candidate);
+ // Since the window already timed out, remove it immediately now.
+ // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter
+ // delays removal on certain conditions, which will leave the stale window in the
+ // stack and marked mWillReplaceWindow=false, so the window will never be removed.
+ service.removeWindowInnerLocked(candidate);
}
}
+ /**
+ * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
+ * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
+ * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
+ * with a queue.
+ */
+ void freezeBounds() {
+ mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
+ }
+
+ /**
+ * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
+ */
+ void unfreezeBounds() {
+ mFrozenBounds.remove();
+ }
+
@Override
void dump(PrintWriter pw, String prefix) {
super.dump(pw, prefix);
@@ -480,6 +525,9 @@
pw.print(" startingDisplayed="); pw.print(startingDisplayed);
pw.print(" startingMoved"); pw.println(startingMoved);
}
+ if (!mFrozenBounds.isEmpty()) {
+ pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 5942198..51787b0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -570,38 +570,19 @@
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval);
pw.print(" layoutNeeded="); pw.println(layoutNeeded);
- for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mStacks.get(stackNdx);
- pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId);
- stack.dump(prefix + " ", pw);
- }
+
pw.println();
pw.println(" Application tokens in top down Z order:");
- int ndx = 0;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mStacks.get(stackNdx);
- pw.print(" mStackId="); pw.println(stack.mStackId);
- ArrayList<Task> tasks = stack.getTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final Task task = tasks.get(taskNdx);
- pw.print(" mTaskId="); pw.println(task.mTaskId);
- AppTokenList tokens = task.mAppTokens;
- for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) {
- final AppWindowToken wtoken = tokens.get(tokenNdx);
- pw.print(" Activity #"); pw.print(tokenNdx);
- pw.print(' '); pw.print(wtoken); pw.println(":");
- wtoken.dump(pw, " ");
- }
- }
+ stack.dump(prefix + " ", pw);
}
- if (ndx == 0) {
- pw.println(" None");
- }
+
pw.println();
if (!mExitingTokens.isEmpty()) {
pw.println();
pw.println(" Exiting tokens:");
- for (int i=mExitingTokens.size()-1; i>=0; i--) {
+ for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
WindowToken token = mExitingTokens.get(i);
pw.print(" Exiting #"); pw.print(i);
pw.print(' '); pw.print(token);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8f3d3e3..7295318 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,11 +18,17 @@
import android.content.Context;
import android.graphics.Rect;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Slog;
-import android.view.IDockDividerVisibilityListener;
+import android.view.DisplayInfo;
+import android.view.IDockedStackListener;
+import android.view.SurfaceControl;
+
+import com.android.server.wm.DimLayer.DimLayerUser;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
@@ -33,7 +39,7 @@
/**
* Keeps information about the docked stack divider.
*/
-public class DockedStackDividerController {
+public class DockedStackDividerController implements DimLayerUser {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
@@ -44,9 +50,10 @@
private WindowState mWindow;
private final Rect mTmpRect = new Rect();
private final Rect mLastRect = new Rect();
- private IDockDividerVisibilityListener mListener;
private boolean mLastVisibility = false;
- private boolean mForceVisibilityReevaluation;
+ private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
+ = new RemoteCallbackList<>();
+ private final DimLayer mDimLayer;
DockedStackDividerController(Context context, DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -54,6 +61,7 @@
com.android.internal.R.dimen.docked_stack_divider_thickness);
mDividerInsets = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_insets);
+ mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
}
boolean isResizing() {
@@ -83,15 +91,16 @@
return;
}
mLastVisibility = visible;
- if (mListener != null) {
- try {
- mListener.onDockDividerVisibilityChanged(visible);
- } catch (RemoteException e) {
- Slog.e(TAG, "visibility call failed: " + e);
- }
+ notifyDockedDividerVisibilityChanged(visible);
+ if (!visible) {
+ setResizeDimLayer(false, INVALID_STACK_ID, 0f);
}
}
+ boolean wasVisible() {
+ return mLastVisibility;
+ }
+
void positionDockedStackedDivider(Rect frame) {
TaskStack stack = mDisplayContent.getDockedStackLocked();
if (stack == null) {
@@ -127,11 +136,76 @@
mLastRect.set(frame);
}
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
- if (mListener != null && listener != null) {
- throw new IllegalStateException("Dock divider visibility listener already set!");
+ void notifyDockedDividerVisibilityChanged(boolean visible) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDividerVisibilityChanged(visible);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
+ }
}
- mListener = listener;
- reevaluateVisibility(true);
+ mDockedStackListeners.finishBroadcast();
+ }
+
+ void notifyDockedStackExistsChanged(boolean exists) {
+ final int size = mDockedStackListeners.beginBroadcast();
+ for (int i = 0; i < size; ++i) {
+ final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+ try {
+ listener.onDockedStackExistsChanged(exists);
+ } catch (RemoteException e) {
+ Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
+ }
+ }
+ mDockedStackListeners.finishBroadcast();
+ }
+
+ void registerDockedStackListener(IDockedStackListener listener) {
+ mDockedStackListeners.register(listener);
+ notifyDockedDividerVisibilityChanged(wasVisible());
+ notifyDockedStackExistsChanged(
+ mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+ }
+
+ void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ SurfaceControl.openTransaction();
+ TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+ boolean visibleAndValid = visible && stack != null;
+ if (visibleAndValid) {
+ stack.getDimBounds(mTmpRect);
+ if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
+ mDimLayer.setBounds(mTmpRect);
+ mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
+ alpha, 0 /* duration */);
+ } else {
+ visibleAndValid = false;
+ }
+ }
+ if (!visibleAndValid) {
+ mDimLayer.hide();
+ }
+ SurfaceControl.closeTransaction();
+ }
+
+ @Override
+ public boolean isFullscreen() {
+ return false;
+ }
+
+ @Override
+ public DisplayInfo getDisplayInfo() {
+ return mDisplayContent.getDisplayInfo();
+ }
+
+ @Override
+ public void getDimBounds(Rect outBounds) {
+ // This dim layer user doesn't need this.
+ }
+
+ @Override
+ public String toShortString() {
+ return TAG;
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index da894818..7b0a8d7 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -35,7 +35,6 @@
import android.util.Slog;
import android.view.Display;
import android.view.DragEvent;
-import android.view.DropPermissionHolder;
import android.view.InputChannel;
import android.view.SurfaceControl;
import android.view.View;
@@ -54,6 +53,8 @@
import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
import com.android.server.wm.WindowManagerService.H;
+import com.android.internal.view.IDropPermissions;
+
import java.util.ArrayList;
/**
@@ -428,7 +429,7 @@
// Tell the drop target about the data. Returns 'true' if we can immediately
// dispatch the global drag-ended message, 'false' if we need to wait for a
// result from the recipient.
- boolean notifyDropLw(WindowState touchedWin, DropPermissionHolder dropPermissionHolder,
+ boolean notifyDropLw(WindowState touchedWin, IDropPermissions dropPermissions,
float x, float y) {
if (mAnimation != null) {
return false;
@@ -449,7 +450,7 @@
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
- null, null, mData, dropPermissionHolder, false);
+ null, null, mData, dropPermissions, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -516,7 +517,7 @@
private static DragEvent obtainDragEvent(WindowState win, int action,
float x, float y, Object localState,
ClipDescription description, ClipData data,
- DropPermissionHolder dropPermissionHolder,
+ IDropPermissions dropPermissions,
boolean result) {
float winX = x - win.mFrame.left;
float winY = y - win.mFrame.top;
@@ -525,7 +526,7 @@
winY *= win.mGlobalScale;
}
return DragEvent.obtain(action, winX, winY, localState, description, data,
- dropPermissionHolder, result);
+ dropPermissions, result);
}
boolean stepAnimationLocked(long currentTimeMs) {
diff --git a/services/core/java/com/android/server/wm/DropPermissionsHandler.java b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
new file mode 100644
index 0000000..68cfaab
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
@@ -0,0 +1,98 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.server.wm;
+
+import android.app.ActivityManagerNative;
+import android.content.ClipData;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.view.IDropPermissions;
+
+import java.util.ArrayList;
+
+class DropPermissionsHandler extends IDropPermissions.Stub {
+
+ private final int mSourceUid;
+ private final String mTargetPackage;
+ private final int mMode;
+ private final int mSourceUserId;
+ private final int mTargetUserId;
+
+ private final ArrayList<Uri> mUris = new ArrayList<Uri>();
+
+ private IBinder mActivityToken = null;
+
+ DropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
+ int sourceUserId, int targetUserId) {
+ mSourceUid = sourceUid;
+ mTargetPackage = targetPackage;
+ mMode = mode;
+ mSourceUserId = sourceUserId;
+ mTargetUserId = targetUserId;
+
+ clipData.collectUris(mUris);
+ }
+
+ @Override
+ public void take(IBinder activityToken) throws RemoteException {
+ if (mActivityToken != null) {
+ return;
+ }
+ mActivityToken = activityToken;
+
+ // Will throw if Activity is not found.
+ IBinder permissionOwner = ActivityManagerNative.getDefault().
+ getUriPermissionOwnerForActivity(mActivityToken);
+
+ long origId = Binder.clearCallingIdentity();
+ try {
+ for (int i = 0; i < mUris.size(); i++) {
+ ActivityManagerNative.getDefault().grantUriPermissionFromOwner(
+ permissionOwner, mSourceUid, mTargetPackage, mUris.get(i), mMode,
+ mSourceUserId, mTargetUserId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void release() throws RemoteException {
+ if (mActivityToken == null) {
+ return;
+ }
+
+ IBinder permissionOwner = null;
+ try {
+ permissionOwner = ActivityManagerNative.getDefault().
+ getUriPermissionOwnerForActivity(mActivityToken);
+ } catch (Exception e) {
+ // Activity is destroyed, permissions already revoked.
+ return;
+ } finally {
+ mActivityToken = null;
+ }
+
+ for (int i = 0; i < mUris.size(); ++i) {
+ ActivityManagerNative.getDefault().revokeUriPermissionFromOwner(
+ permissionOwner, mUris.get(i), mMode, mSourceUserId);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 72a8343..72970f6 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,6 +61,10 @@
// Content limits relative to the DisplayContent this sits in.
private Rect mBounds = new Rect();
+ final Rect mPreparedFrozenBounds = new Rect();
+
+ // Bounds used to calculate the insets.
+ private final Rect mTempInsetBounds = new Rect();
// Device rotation as of the last time {@link #mBounds} was set.
int mRotation;
@@ -197,8 +201,7 @@
boolean removeAppToken(AppWindowToken wtoken) {
boolean removed = mAppTokens.remove(wtoken);
if (mAppTokens.size() == 0) {
- EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
- "removeAppToken: last token");
+ EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
if (mDeferRemoval) {
removeLocked();
}
@@ -267,6 +270,26 @@
return boundsChange;
}
+ /**
+ * Sets the bounds used to calculate the insets. See
+ * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+ */
+ void setTempInsetBounds(Rect tempInsetBounds) {
+ if (tempInsetBounds != null) {
+ mTempInsetBounds.set(tempInsetBounds);
+ } else {
+ mTempInsetBounds.setEmpty();
+ }
+ }
+
+ /**
+ * Gets the bounds used to calculate the insets. See
+ * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+ */
+ void getTempInsetBounds(Rect out) {
+ out.set(mTempInsetBounds);
+ }
+
void setResizeable(boolean resizeable) {
mResizeable = resizeable;
}
@@ -285,10 +308,20 @@
}
if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
resizeWindows();
+ } else {
+ moveWindows();
}
return true;
}
+ /**
+ * Prepares the task bounds to be frozen with the current size. See
+ * {@link AppWindowToken#freezeBounds}.
+ */
+ void prepareFreezingBounds() {
+ mPreparedFrozenBounds.set(mBounds);
+ }
+
boolean scrollLocked(Rect bounds) {
// shift the task bound if it doesn't fully cover the stack area
mStack.getDimBounds(mTmpRect);
@@ -355,7 +388,6 @@
mStack.getDisplayContent().getLogicalDisplayRect(out);
}
-
/**
* Calculate the maximum visible area of this task. If the task has only one app,
* the result will be visible frame of that app. If the task has more than one apps,
@@ -463,13 +495,24 @@
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
- if (DEBUG_RESIZE) Slog.d(TAG_WM, "setBounds: Resizing " + win);
+ if (DEBUG_RESIZE) Slog.d(TAG_WM, "resizeWindows: Resizing " + win);
resizingWindows.add(win);
}
}
}
}
+ void moveWindows() {
+ for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
+ final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ if (DEBUG_RESIZE) Slog.d(TAG_WM, "moveWindows: Moving " + win);
+ win.mMovedByResize = true;
+ }
+ }
+ }
+
/**
* Cancels any running app transitions associated with the task.
*/
@@ -560,11 +603,23 @@
return "Task=" + mTaskId;
}
- public void printTo(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("taskId="); pw.println(mTaskId);
- pw.print(prefix + prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
- pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
- pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval);
- pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens);
+ public void dump(String prefix, PrintWriter pw) {
+ final String doublePrefix = prefix + " ";
+
+ pw.println(prefix + "taskId=" + mTaskId);
+ pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
+ pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
+ pw.println(doublePrefix + "mdr=" + mDeferRemoval);
+ pw.println(doublePrefix + "appTokens=" + mAppTokens);
+ pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
+
+ final String triplePrefix = doublePrefix + " ";
+
+ for (int i = mAppTokens.size() - 1; i >= 0; i--) {
+ final AppWindowToken wtoken = mAppTokens.get(i);
+ pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
+ wtoken.dump(pw, triplePrefix);
+ }
+
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b961879..fc6ad70 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -114,7 +114,8 @@
* @return True if the stack bounds was changed.
* */
boolean setBounds(
- Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+ Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
if (!setBounds(stackBounds)) {
return false;
}
@@ -136,6 +137,9 @@
task.scrollLocked(mTmpRect);
} else {
task.setBounds(bounds, config);
+ task.setTempInsetBounds(
+ taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
+ : null);
}
} else {
Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
@@ -144,6 +148,13 @@
return true;
}
+ void prepareFreezingTaskBounds() {
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final Task task = mTasks.get(taskNdx);
+ task.prepareFreezingBounds();
+ }
+ }
+
boolean isFullscreenBounds(Rect bounds) {
if (mDisplayContent == null || bounds == null) {
return true;
@@ -608,16 +619,15 @@
}
public void dump(String prefix, PrintWriter pw) {
- pw.print(prefix); pw.print("mStackId="); pw.println(mStackId);
- pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach);
- pw.print(prefix); pw.print("mFullscreen="); pw.println(mFullscreen);
- pw.print(prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
- for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) {
- pw.print(prefix);
- mTasks.get(taskNdx).printTo(prefix + " ", pw);
+ pw.println(prefix + "mStackId=" + mStackId);
+ pw.println(prefix + "mDeferDetach=" + mDeferDetach);
+ pw.println(prefix + "mFullscreen=" + mFullscreen);
+ pw.println(prefix + "mBounds=" + mBounds.toShortString());
+ for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
+ mTasks.get(taskNdx).dump(prefix + " ", pw);
}
if (mAnimationBackgroundSurface.isDimming()) {
- pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:");
+ pw.println(prefix + "mWindowAnimationBackgroundSurface:");
mAnimationBackgroundSurface.printTo(prefix + " ", pw);
}
if (!mExitingAppTokens.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index af109d4..98033f6 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -20,6 +20,7 @@
import android.graphics.Region;
import android.view.DisplayInfo;
import android.view.GestureDetector;
+import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy.PointerEventListener;
@@ -108,7 +109,8 @@
final int x = (int) motionEvent.getX();
final int y = (int) motionEvent.getY();
final Task task = mDisplayContent.findTaskForControlPoint(x, y);
- if (task == null) {
+ InputDevice inputDevice = motionEvent.getDevice();
+ if (task == null || inputDevice == null) {
mPointerIconShape = STYLE_NOT_SPECIFIED;
break;
}
@@ -130,7 +132,7 @@
}
if (mPointerIconShape != iconShape) {
mPointerIconShape = iconShape;
- motionEvent.getDevice().setPointerShape(iconShape);
+ inputDevice.setPointerShape(iconShape);
}
} else {
mPointerIconShape = STYLE_NOT_SPECIFIED;
@@ -139,7 +141,10 @@
case MotionEvent.ACTION_HOVER_EXIT:
mPointerIconShape = STYLE_NOT_SPECIFIED;
- motionEvent.getDevice().setPointerShape(STYLE_DEFAULT);
+ InputDevice inputDevice = motionEvent.getDevice();
+ if (inputDevice != null) {
+ inputDevice.setPointerShape(STYLE_DEFAULT);
+ }
break;
case MotionEvent.ACTION_UP:
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 6a5183f..62d4f36 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -782,7 +782,7 @@
SurfaceControl.openTransaction();
try {
for (int i = mService.mDisplayContents.size() - 1; i >= 0; i--) {
- DisplayContent display = mService.mDisplayContents.get(i);
+ DisplayContent display = mService.mDisplayContents.valueAt(i);
final WindowList windows = mService.getWindowListLocked(display.getDisplayId());
for (int j = windows.size() - 1; j >= 0; j--) {
windows.get(j).maybeRemoveReplacedWindow();
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
new file mode 100644
index 0000000..2cf2618
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.app.ActivityManager.StackId;
+import android.util.Slog;
+import android.view.Display;
+
+import java.io.PrintWriter;
+
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+
+/**
+ * Controller for assigning layers to windows on the display.
+ *
+ * This class encapsulates general algorithm for assigning layers and special rules that we need to
+ * apply on top. The general algorithm goes through windows from bottom to the top and the higher
+ * the window is, the higher layer is assigned. The final layer is equal to base layer +
+ * adjustment from the order. This means that the window list is assumed to be ordered roughly by
+ * the base layer (there are exceptions, e.g. due to keyguard and wallpaper and they need to be
+ * handled with care, because they break the algorithm).
+ *
+ * On top of the general algorithm we add special rules, that govern such amazing things as:
+ * <li>IME (which has higher base layer, but will be positioned above application windows)</li>
+ * <li>docked/pinned windows (that need to be lifted above other application windows, including
+ * animations)
+ * <li>dock divider (which needs to live above applications, but below IME)</li>
+ * <li>replaced windows, which need to live above their normal level, because they anticipate
+ * an animation</li>.
+ */
+public class WindowLayersController {
+ private final WindowManagerService mService;
+
+ private int mInputMethodAnimLayerAdjustment;
+
+ public WindowLayersController(WindowManagerService service) {
+ mService = service;
+ }
+
+ private int mHighestApplicationLayer = 0;
+ private WindowState mPinnedWindow = null;
+ private WindowState mDockedWindow = null;
+ private WindowState mDockDivider = null;
+ private WindowState mReplacingWindow = null;
+
+ final void assignLayersLocked(WindowList windows) {
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
+ new RuntimeException("here").fillInStackTrace());
+
+ clear();
+ int curBaseLayer = 0;
+ int curLayer = 0;
+ boolean anyLayerChanged = false;
+ for (int i = 0, windowCount = windows.size(); i < windowCount; i++) {
+ final WindowState w = windows.get(i);
+ boolean layerChanged = false;
+
+ int oldLayer = w.mLayer;
+ if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
+ curLayer += WINDOW_LAYER_MULTIPLIER;
+ w.mLayer = curLayer;
+ } else {
+ curBaseLayer = curLayer = w.mBaseLayer;
+ w.mLayer = curLayer;
+ }
+ if (w.mLayer != oldLayer) {
+ layerChanged = true;
+ anyLayerChanged = true;
+ }
+
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ oldLayer = winAnimator.mAnimLayer;
+ winAnimator.mAnimLayer = w.mLayer + w.getAnimLayerAdjustment() +
+ getSpecialWindowAnimLayerAdjustment(w);
+ if (winAnimator.mAnimLayer != oldLayer) {
+ layerChanged = true;
+ anyLayerChanged = true;
+ }
+
+ if (w.mAppToken != null) {
+ mHighestApplicationLayer = Math.max(mHighestApplicationLayer,
+ winAnimator.mAnimLayer);
+ }
+ collectSpecialWindows(w);
+
+ if (layerChanged) {
+ w.scheduleAnimationIfDimming();
+ }
+ }
+
+ adjustSpecialWindows();
+
+ //TODO (multidisplay): Magnification is supported only for the default display.
+ if (mService.mAccessibilityController != null && anyLayerChanged
+ && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onWindowLayersChangedLocked();
+ }
+
+ if (DEBUG_LAYERS) logDebugLayers(windows);
+ }
+
+ void setInputMethodAnimLayerAdjustment(int adj) {
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
+ mInputMethodAnimLayerAdjustment = adj;
+ final WindowState imw = mService.mInputMethodWindow;
+ if (imw != null) {
+ imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
+ + " anim layer: " + imw.mWinAnimator.mAnimLayer);
+ for (int i = imw.mChildWindows.size() - 1; i >= 0; i--) {
+ final WindowState childWindow = imw.mChildWindows.get(i);
+ childWindow.mWinAnimator.mAnimLayer = childWindow.mLayer + adj;
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + childWindow
+ + " anim layer: " + childWindow.mWinAnimator.mAnimLayer);
+ }
+ }
+ for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) {
+ final WindowState dialog = mService.mInputMethodDialogs.get(i);
+ dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj;
+ if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
+ + " anim layer: " + dialog.mWinAnimator.mAnimLayer);
+ }
+ }
+
+ int getSpecialWindowAnimLayerAdjustment(WindowState win) {
+ if (win.mIsImWindow) {
+ return mInputMethodAnimLayerAdjustment;
+ } else if (win.mIsWallpaper) {
+ return mService.mWallpaperControllerLocked.getAnimLayerAdjustment();
+ }
+ return 0;
+ }
+
+ /**
+ * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
+ * above all application surfaces.
+ */
+ int getResizeDimLayer() {
+ return mDockDivider.mLayer - 1;
+ }
+
+ private void logDebugLayers(WindowList windows) {
+ for (int i = 0, n = windows.size(); i < n; i++) {
+ final WindowState w = windows.get(i);
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ Slog.v(TAG_WM, "Assign layer " + w + ": " + "mBase=" + w.mBaseLayer
+ + " mLayer=" + w.mLayer + (w.mAppToken == null
+ ? "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
+ + " =mAnimLayer=" + winAnimator.mAnimLayer);
+ }
+ }
+
+ private void clear() {
+ mHighestApplicationLayer = 0;
+ mPinnedWindow = null;
+ mDockedWindow = null;
+ mDockDivider = null;
+ }
+
+ private void collectSpecialWindows(WindowState w) {
+ if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
+ mDockDivider = w;
+ } else {
+ final TaskStack stack = w.getStack();
+ if (stack == null) {
+ return;
+ }
+ if (stack.mStackId == StackId.PINNED_STACK_ID) {
+ mPinnedWindow = w;
+ } else if (stack.mStackId == StackId.DOCKED_STACK_ID) {
+ mDockedWindow = w;
+ }
+ }
+ }
+
+ private void adjustSpecialWindows() {
+ int layer = mHighestApplicationLayer + 1;
+ // For pinned and docked stack window, we want to make them above other windows
+ // also when these windows are animating.
+ layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, layer);
+
+ // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
+ // below the divider but above the app windows. It needs to be below the divider in because
+ // the divider sometimes overlaps the app windows.
+ layer++;
+ layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
+ // We know that we will be animating a relaunching window in the near future,
+ // which will receive a z-order increase. We want the replaced window to
+ // immediately receive the same treatment, e.g. to be above the dock divider.
+ layer = assignAndIncreaseLayerIfNeeded(mReplacingWindow, layer);
+ layer = assignAndIncreaseLayerIfNeeded(mPinnedWindow, layer);
+ }
+
+ private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
+ if (win != null) {
+ win.mLayer = layer;
+ win.mWinAnimator.mAnimLayer = layer;
+ layer++;
+ }
+ return layer;
+ }
+
+ void dump(PrintWriter pw, String s) {
+ if (mInputMethodAnimLayerAdjustment != 0 ||
+ mService.mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
+ pw.print(" mInputMethodAnimLayerAdjustment=");
+ pw.print(mInputMethodAnimLayerAdjustment);
+ pw.print(" mWallpaperAnimLayerAdjustment=");
+ pw.println(mService.mWallpaperControllerLocked.getAnimLayerAdjustment());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 845100d..4c3a422 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,7 +35,7 @@
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG = false;
- static final boolean DEBUG_ADD_REMOVE = false;
+ static final boolean DEBUG_ADD_REMOVE = true;
static final boolean DEBUG_FOCUS = true;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
static final boolean DEBUG_ANIM = false;
@@ -50,8 +50,8 @@
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
- static final boolean DEBUG_APP_TRANSITIONS = false;
- static final boolean DEBUG_STARTING_WINDOW = false;
+ static final boolean DEBUG_APP_TRANSITIONS = true;
+ static final boolean DEBUG_STARTING_WINDOW = true;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 456c416..792f11f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,78 +16,6 @@
package com.android.server.wm;
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.StatusBarManager.DISABLE_MASK;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
import android.Manifest;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
@@ -129,6 +57,7 @@
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -153,11 +82,10 @@
import android.view.Choreographer;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.DropPermissionHolder;
import android.view.Gravity;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
import android.view.IInputFilter;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
@@ -227,9 +155,83 @@
import java.util.Iterator;
import java.util.List;
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowManagerService" : TAG_WM;
+
static final int LAYOUT_REPEAT_THRESHOLD = 4;
static final boolean PROFILE_ORIENTATION = false;
@@ -567,7 +569,6 @@
/** If true hold off on modifying the animation layer of mInputMethodTarget */
boolean mInputMethodTargetWaitingAnim;
- int mInputMethodAnimLayerAdjustment;
WindowState mInputMethodWindow = null;
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<>();
@@ -577,31 +578,23 @@
final ArrayList<WindowState> mTmpWindows = new ArrayList<>();
boolean mHardKeyboardAvailable;
- boolean mShowImeWithHardKeyboard;
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
SettingsObserver mSettingsObserver;
private final class SettingsObserver extends ContentObserver {
- private final Uri mShowImeWithHardKeyboardUri =
- Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
-
private final Uri mDisplayInversionEnabledUri =
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
public SettingsObserver() {
super(new Handler());
ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this,
- UserHandle.USER_ALL);
resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
UserHandle.USER_ALL);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (mShowImeWithHardKeyboardUri.equals(uri)) {
- updateShowImeWithHardKeyboard();
- } else if (mDisplayInversionEnabledUri.equals(uri)) {
+ if (mDisplayInversionEnabledUri.equals(uri)) {
updateCircularDisplayMaskIfNeeded();
}
}
@@ -609,6 +602,8 @@
WallpaperController mWallpaperControllerLocked;
+ final WindowLayersController mLayersController;
+
boolean mAnimateWallpaperWithTarget;
AppWindowToken mFocusedApp = null;
@@ -758,13 +753,12 @@
private boolean completeDropLw(float x, float y) {
WindowState dropTargetWin = mDragState.getDropTargetWinLw(x, y);
- DropPermissionHolder dropPermissionHolder = null;
+ DropPermissionsHandler dropPermissions = null;
if (dropTargetWin != null &&
(mDragState.mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
(mDragState.mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
- dropPermissionHolder = new DropPermissionHolder(
+ dropPermissions = new DropPermissionsHandler(
mDragState.mData,
- mActivityManager,
mDragState.mUid,
dropTargetWin.getOwningPackage(),
mDragState.mFlags & DRAG_FLAGS_URI_PERMISSIONS,
@@ -772,7 +766,7 @@
UserHandle.getUserId(dropTargetWin.getOwningUid()));
}
- return mDragState.notifyDropLw(dropTargetWin, dropPermissionHolder, x, y);
+ return mDragState.notifyDropLw(dropTargetWin, dropPermissions, x, y);
}
/**
@@ -882,6 +876,7 @@
mWallpaperControllerLocked = new WallpaperController(this);
mWindowPlacerLocked = new WindowSurfacePlacer(this);
+ mLayersController = new WindowLayersController(this);
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
@@ -943,7 +938,6 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
mSettingsObserver = new SettingsObserver();
- updateShowImeWithHardKeyboard();
mHoldingScreenWakeLock = mPowerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
@@ -1511,9 +1505,10 @@
mInputMethodTarget = w;
mInputMethodTargetWaitingAnim = false;
if (w.mAppToken != null) {
- setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment);
+ mLayersController.setInputMethodAnimLayerAdjustment(
+ w.mAppToken.mAppAnimator.animLayerAdjustment);
} else {
- setInputMethodAnimLayerAdjustment(0);
+ mLayersController.setInputMethodAnimLayerAdjustment(0);
}
}
return i+1;
@@ -1522,7 +1517,7 @@
if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to null."
+ (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4)));
mInputMethodTarget = null;
- setInputMethodAnimLayerAdjustment(0);
+ mLayersController.setInputMethodAnimLayerAdjustment(0);
}
return -1;
}
@@ -1544,33 +1539,6 @@
moveInputMethodDialogsLocked(pos);
}
- void setInputMethodAnimLayerAdjustment(int adj) {
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
- mInputMethodAnimLayerAdjustment = adj;
- WindowState imw = mInputMethodWindow;
- if (imw != null) {
- imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
- + " anim layer: " + imw.mWinAnimator.mAnimLayer);
- int wi = imw.mChildWindows.size();
- while (wi > 0) {
- wi--;
- WindowState cw = imw.mChildWindows.get(wi);
- cw.mWinAnimator.mAnimLayer = cw.mLayer + adj;
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + cw
- + " anim layer: " + cw.mWinAnimator.mAnimLayer);
- }
- }
- int di = mInputMethodDialogs.size();
- while (di > 0) {
- di --;
- imw = mInputMethodDialogs.get(di);
- imw.mWinAnimator.mAnimLayer = imw.mLayer + adj;
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
- + " anim layer: " + imw.mWinAnimator.mAnimLayer);
- }
- }
-
private int tmpRemoveWindowLocked(int interestingPos, WindowState win) {
WindowList windows = win.getWindowList();
int wpos = windows.indexOf(win);
@@ -1769,7 +1737,7 @@
}
if (needAssignLayers) {
- assignLayersLocked(windows);
+ mLayersController.assignLayersLocked(windows);
}
return true;
@@ -2061,7 +2029,7 @@
moveInputMethodWindowsIfNeededLocked(false);
}
- assignLayersLocked(displayContent.getWindowList());
+ mLayersController.assignLayersLocked(displayContent.getWindowList());
// Don't do layout here, the window must call
// relayout to be displayed, so we'll do it there.
@@ -2388,7 +2356,7 @@
if (windows != null) {
windows.remove(win);
if (!mWindowPlacerLocked.isInLayout()) {
- assignLayersLocked(windows);
+ mLayersController.assignLayersLocked(windows);
win.setDisplayLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
if (win.mAppToken != null) {
@@ -2454,13 +2422,17 @@
}
}
- void setInsetsWindow(Session session, IWindow client,
- int touchableInsets, Rect contentInsets,
+ void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
long origId = Binder.clearCallingIdentity();
try {
synchronized (mWindowMap) {
WindowState w = windowForClientLocked(session, client, false);
+ if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w
+ + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets
+ + ", visibleInsets=" + w.mGivenVisibleInsets + " -> " + visibleInsets
+ + ", touchableRegion=" + w.mGivenTouchableRegion + " -> " + touchableRegion
+ + ", touchableInsets " + w.mTouchableInsets + " -> " + touchableInsets);
if (w != null) {
w.mGivenInsetsPending = false;
w.mGivenContentInsets.set(contentInsets);
@@ -2743,7 +2715,7 @@
// its layer recomputed. However, if the IME was hidden
// and isn't actually moved in the list, its layer may be
// out of data so we make sure to recompute it.
- assignLayersLocked(win.getWindowList());
+ mLayersController.assignLayersLocked(win.getWindowList());
}
if (wallpaperMayMove) {
@@ -3231,7 +3203,8 @@
public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
- Rect taskBounds, Configuration config, boolean cropWindowsToStack) {
+ Rect taskBounds, Configuration config, boolean cropWindowsToStack,
+ boolean alwaysFocusable) {
if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
"addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3266,6 +3239,7 @@
(ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
atoken.mLaunchTaskBehind = launchTaskBehind;
atoken.mCropWindowsToStack = cropWindowsToStack;
+ atoken.mAlwaysFocusable = alwaysFocusable;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -3905,7 +3879,7 @@
return false;
}
WindowState startingWindow = ttoken.startingWindow;
- if (startingWindow != null) {
+ if (startingWindow != null && ttoken.startingView != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
mSkipAppTransitionAnimation = true;
@@ -4586,7 +4560,7 @@
if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/)) {
- assignLayersLocked(displayContent.getWindowList());
+ mLayersController.assignLayersLocked(displayContent.getWindowList());
}
mInputMonitor.setUpdateInputWindowsNeededLw();
@@ -4679,6 +4653,10 @@
if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
stack = new TaskStack(this, stackId);
mStackIdToStack.put(stackId, stack);
+ if (stackId == DOCKED_STACK_ID) {
+ getDefaultDisplayContentLocked().mDividerControllerLocked
+ .notifyDockedStackExistsChanged(true);
+ }
}
stack.attachDisplayContent(displayContent);
displayContent.attachStack(stack, onTop);
@@ -4704,6 +4682,10 @@
void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
displayContent.detachStack(stack);
stack.detachDisplay();
+ if (stack.mStackId == DOCKED_STACK_ID) {
+ getDefaultDisplayContentLocked().mDividerControllerLocked
+ .notifyDockedStackExistsChanged(false);
+ }
}
public void detachStack(int stackId) {
@@ -4850,14 +4832,16 @@
* @return True if the stack is now fullscreen.
* */
public boolean resizeStack(int stackId, Rect bounds,
- SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+ SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+ SparseArray<Rect> taskTempInsetBounds) {
synchronized (mWindowMap) {
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
throw new IllegalArgumentException("resizeStack: stackId " + stackId
+ " not found.");
}
- if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
+ if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+ && stack.isVisibleLocked()) {
stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
mWindowPlacerLocked.performSurfacePlacement();
@@ -4866,6 +4850,17 @@
}
}
+ public void prepareFreezingTaskBounds(int stackId) {
+ synchronized (mWindowMap) {
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId
+ + " not found.");
+ }
+ stack.prepareFreezingTaskBounds();
+ }
+ }
+
public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
Configuration config) {
synchronized (mWindowMap) {
@@ -7107,9 +7102,6 @@
mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
}
- if (mShowImeWithHardKeyboard) {
- config.keyboard = Configuration.KEYBOARD_NOKEYS;
- }
// Let the policy update hidden states.
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
@@ -7118,18 +7110,6 @@
mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
}
- public void updateShowImeWithHardKeyboard() {
- synchronized (mWindowMap) {
- final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0,
- mCurrentUserId) == 1;
- if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) {
- mShowImeWithHardKeyboard = showImeWithHardKeyboard;
- mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
- }
- }
- }
-
void notifyHardKeyboardStatusChange() {
final boolean available;
final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener;
@@ -8102,7 +8082,7 @@
case WINDOW_REPLACEMENT_TIMEOUT: {
final AppWindowToken token = (AppWindowToken) msg.obj;
synchronized (mWindowMap) {
- token.clearTimedoutReplaceesLocked();
+ token.clearTimedoutReplacesLocked();
}
}
break;
@@ -8662,102 +8642,6 @@
Arrays.fill(mRebuildTmp, null);
}
- final void assignLayersLocked(WindowList windows) {
- int N = windows.size();
- int curBaseLayer = 0;
- int curLayer = 0;
- int i;
-
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assigning layers based on windows=" + windows,
- new RuntimeException("here").fillInStackTrace());
-
- boolean anyLayerChanged = false;
-
- for (i=0; i<N; i++) {
- final WindowState w = windows.get(i);
- final WindowStateAnimator winAnimator = w.mWinAnimator;
- boolean layerChanged = false;
- int oldLayer = w.mLayer;
- if (w.mBaseLayer == curBaseLayer || w.mIsImWindow || (i > 0 && w.mIsWallpaper)) {
- curLayer += WINDOW_LAYER_MULTIPLIER;
- w.mLayer = curLayer;
- } else {
- curBaseLayer = curLayer = w.mBaseLayer;
- w.mLayer = curLayer;
- }
- if (w.mLayer != oldLayer) {
- layerChanged = true;
- anyLayerChanged = true;
- }
- final AppWindowToken wtoken = w.mAppToken;
- oldLayer = winAnimator.mAnimLayer;
- if (w.mTargetAppToken != null) {
- winAnimator.mAnimLayer =
- w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
- } else if (wtoken != null) {
- winAnimator.mAnimLayer =
- w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
- forceHigherLayerIfNeeded(w, winAnimator, wtoken);
- } else {
- winAnimator.mAnimLayer = w.mLayer;
- }
- if (w.mIsImWindow) {
- winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
- } else if (w.mIsWallpaper) {
- winAnimator.mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
- }
- if (winAnimator.mAnimLayer != oldLayer) {
- layerChanged = true;
- anyLayerChanged = true;
- }
- final DimLayer.DimLayerUser dimLayerUser = w.getDimLayerUser();
- final DisplayContent displayContent = w.getDisplayContent();
- if (layerChanged && dimLayerUser != null && displayContent != null &&
- displayContent.mDimLayerController.isDimming(dimLayerUser, winAnimator)) {
- // Force an animation pass just to update the mDimLayer layer.
- scheduleAnimationLocked();
- }
- if (DEBUG_LAYERS) Slog.v(TAG_WM, "Assign layer " + w + ": "
- + "mBase=" + w.mBaseLayer
- + " mLayer=" + w.mLayer
- + (wtoken == null ?
- "" : " mAppLayer=" + wtoken.mAppAnimator.animLayerAdjustment)
- + " =mAnimLayer=" + winAnimator.mAnimLayer);
- //System.out.println(
- // "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
- }
-
- //TODO (multidisplay): Magnification is supported only for the default display.
- if (mAccessibilityController != null && anyLayerChanged
- && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
- mAccessibilityController.onWindowLayersChangedLocked();
- }
- }
-
- private void forceHigherLayerIfNeeded(WindowState w, WindowStateAnimator winAnimator,
- AppWindowToken wtoken) {
- boolean force = false;
-
- if (w.mWillReplaceWindow) {
- // We know that we will be animating a relaunching window in the near future,
- // which will receive a z-order increase. We want the replaced window to
- // immediately receive the same treatment, e.g. to be above the dock divider.
- force = true;
- }
- if (!force) {
- final TaskStack stack = w.getStack();
- if (stack != null && (StackId.shouldIncreaseApplicationWindowLayer(stack.mStackId))) {
- // For pinned and docked stack window, we want to make them above other windows
- // also when these windows are animating.
- force = true;
- }
- }
- if (force) {
- w.mLayer += TYPE_LAYER_OFFSET;
- winAnimator.mAnimLayer += TYPE_LAYER_OFFSET;
- }
- }
-
void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
// If the screen is currently frozen or off, then keep
// it frozen/off until this window draws at its new
@@ -9128,7 +9012,7 @@
} else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
// Client will do the layout, but we need to assign layers
// for handleNewWindowLocked() below.
- assignLayersLocked(displayContent.getWindowList());
+ mLayersController.assignLayersLocked(displayContent.getWindowList());
}
}
@@ -9202,8 +9086,8 @@
if (wtoken == token) {
break;
}
- if (mFocusedApp == token && token.stackCanReceiveKeys()) {
- // Whoops, we are below the focused app whose stack can receive keys...
+ if (mFocusedApp == token && token.windowsAreFocusable()) {
+ // Whoops, we are below the focused app whose windows are focusable...
// No focus for you!!!
if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
"findFocusedWindow: Reached focused app=" + mFocusedApp);
@@ -9588,6 +9472,32 @@
}
}
+ public void notifyAppRelaunching(IBinder token) {
+ synchronized (mWindowMap) {
+ AppWindowToken appWindow = findAppWindowToken(token);
+ if (canFreezeBounds(appWindow)) {
+ appWindow.freezeBounds();
+ }
+ }
+ }
+
+ public void notifyAppRelaunchingFinished(IBinder token) {
+ synchronized (mWindowMap) {
+ AppWindowToken appWindow = findAppWindowToken(token);
+ if (canFreezeBounds(appWindow)) {
+ appWindow.unfreezeBounds();
+ }
+ }
+ }
+
+ private boolean canFreezeBounds(AppWindowToken appWindow) {
+
+ // For freeform windows, we can't freeze the bounds at the moment because this would make
+ // the resizing unresponsive.
+ return appWindow != null && appWindow.mTask != null
+ && !appWindow.mTask.inFreeformWorkspace();
+ }
+
void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
@@ -9816,13 +9726,7 @@
}
mWindowPlacerLocked.dump(pw, " ");
mWallpaperControllerLocked.dump(pw, " ");
- if (mInputMethodAnimLayerAdjustment != 0 ||
- mWallpaperControllerLocked.getAnimLayerAdjustment() != 0) {
- pw.print(" mInputMethodAnimLayerAdjustment=");
- pw.print(mInputMethodAnimLayerAdjustment);
- pw.print(" mWallpaperAnimLayerAdjustment=");
- pw.println(mWallpaperControllerLocked.getAnimLayerAdjustment());
- }
+ mLayersController.dump(pw, " ");
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
if (needsLayout()) {
@@ -9862,6 +9766,10 @@
if ("visible".equals(name) || "visible-apps".equals(name)) {
final boolean appsOnly = "visible-apps".equals(name);
synchronized(mWindowMap) {
+ if (appsOnly) {
+ dumpDisplayContentsLocked(pw, true);
+ }
+
final int numDisplays = mDisplayContents.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final WindowList windowList =
@@ -10258,16 +10166,40 @@
synchronized (mWindowMap) {
appWindowToken = findAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.isVisible()) {
- Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+ Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ + token);
return;
}
appWindowToken.setReplacingWindows(animate);
}
+ }
- if (appWindowToken != null) {
- mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
- mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
- WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+ /**
+ * If we're replacing the window, schedule a timer to clear the replaced window
+ * after a timeout, in case the replacing window is not coming.
+ *
+ * If we're not replacing the window, clear the replace window settings of the app.
+ *
+ * @param token Application token for the activity whose window might be replaced.
+ * @param replacing Whether the window is being replaced or not.
+ */
+ public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
+ AppWindowToken appWindowToken = null;
+ synchronized (mWindowMap) {
+ appWindowToken = findAppWindowToken(token);
+ if (appWindowToken == null) {
+ Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
+ + token);
+ return;
+ }
+ if (replacing) {
+ mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
+ mH.sendMessageDelayed(
+ mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
+ WINDOW_REPLACEMENT_TIMEOUT_DURATION);
+ } else {
+ appWindowToken.resetReplacingWindows();
+ }
}
}
@@ -10287,6 +10219,14 @@
}
}
+ @Override
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+ synchronized (mWindowMap) {
+ getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
+ visible, targetStackId, alpha);
+ }
+ }
+
public void setTaskResizeable(int taskId, boolean resizeable) {
synchronized (mWindowMap) {
Task task = mTaskIdToTask.get(taskId);
@@ -10305,26 +10245,14 @@
}
@Override
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) {
if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
- "registerDockDividerVisibilityListener()")) {
+ "registerDockedStackListener()")) {
return;
}
// TODO(multi-display): The listener is registered on the default display only.
- final DockedStackDividerController controller =
- getDefaultDisplayContentLocked().getDockedDividerController();
- controller.registerDockDividerVisibilityListener(listener);
- try {
- listener.asBinder().linkToDeath(new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- getDefaultDisplayContentLocked().getDockedDividerController()
- .registerDockDividerVisibilityListener(null);
- }
- }, 0);
- } catch (RemoteException e) {
- controller.registerDockDividerVisibilityListener(null);
- }
+ getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
+ listener);
}
private final class LocalService extends WindowManagerInternal {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index e4a6806..b7fd60f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -74,6 +74,7 @@
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -308,6 +309,12 @@
// possible to draw.
final Rect mOutsetFrame = new Rect();
+ /**
+ * Usually empty. Set to the task's tempInsetFrame. See
+ *{@link android.app.IActivityManager#resizeDockedStack}.
+ */
+ final Rect mInsetFrame = new Rect();
+
boolean mContentChanged;
// If a window showing a wallpaper: the requested offset for the
@@ -416,6 +423,8 @@
// the window is added and unset when this window reports its first draw.
WindowState mReplacingWindow = null;
+ // Whether this window is being moved via the resize API
+ boolean mMovedByResize;
/**
* Wake lock for drawing.
* Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -603,10 +612,26 @@
mHaveFrame = true;
final Task task = getTask();
- final boolean nonFullscreenTask = task != null && !task.isFullscreen();
+ final boolean fullscreenTask = task == null || task.isFullscreen();
final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
- if (nonFullscreenTask) {
+
+ if (fullscreenTask || (isChildWindow()
+ && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
+ // We use the parent frame as the containing frame for fullscreen and child windows
+ mContainingFrame.set(pf);
+ mDisplayFrame.set(df);
+ mInsetFrame.setEmpty();
+ } else {
task.getBounds(mContainingFrame);
+ task.getTempInsetBounds(mInsetFrame);
+ if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
+
+ // If the bounds are frozen, we still want to translate the window freely and only
+ // freeze the size.
+ Rect frozen = mAppToken.mFrozenBounds.peek();
+ mContainingFrame.right = mContainingFrame.left + frozen.width();
+ mContainingFrame.bottom = mContainingFrame.top + frozen.height();
+ }
final WindowState imeWin = mService.mInputMethodWindow;
if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
&& mContainingFrame.bottom > cf.bottom) {
@@ -623,9 +648,6 @@
}
}
mDisplayFrame.set(mContainingFrame);
- } else {
- mContainingFrame.set(pf);
- mDisplayFrame.set(df);
}
final int pw = mContainingFrame.width();
@@ -668,6 +690,12 @@
mOutsets.set(0, 0, 0, 0);
}
+ // Denotes the actual frame used to calculate the insets. When resizing in docked mode,
+ // we'd like to freeze the layout, so we also need to freeze the insets temporarily. By the
+ // notion of a task having a different inset frame, we can achieve that while still moving
+ // the task around.
+ final Rect frame = !mInsetFrame.isEmpty() ? mInsetFrame : mFrame;
+
// Make sure the content and visible frames are inside of the
// final window frame.
if (freeformWorkspace && !mFrame.isEmpty()) {
@@ -703,42 +731,69 @@
mContentFrame.set(mFrame);
}
} else {
- mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
- Math.max(mContentFrame.top, mFrame.top),
- Math.min(mContentFrame.right, mFrame.right),
- Math.min(mContentFrame.bottom, mFrame.bottom));
+ mContentFrame.set(Math.max(mContentFrame.left, frame.left),
+ Math.max(mContentFrame.top, frame.top),
+ Math.min(mContentFrame.right, frame.right),
+ Math.min(mContentFrame.bottom, frame.bottom));
- mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
- Math.max(mVisibleFrame.top, mFrame.top),
- Math.min(mVisibleFrame.right, mFrame.right),
- Math.min(mVisibleFrame.bottom, mFrame.bottom));
+ mVisibleFrame.set(Math.max(mVisibleFrame.left, frame.left),
+ Math.max(mVisibleFrame.top, frame.top),
+ Math.min(mVisibleFrame.right, frame.right),
+ Math.min(mVisibleFrame.bottom, frame.bottom));
- mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
- Math.max(mStableFrame.top, mFrame.top),
- Math.min(mStableFrame.right, mFrame.right),
- Math.min(mStableFrame.bottom, mFrame.bottom));
+ mStableFrame.set(Math.max(mStableFrame.left, frame.left),
+ Math.max(mStableFrame.top, frame.top),
+ Math.min(mStableFrame.right, frame.right),
+ Math.min(mStableFrame.bottom, frame.bottom));
}
- mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
- Math.max(mOverscanFrame.top - mFrame.top, 0),
- Math.max(mFrame.right - mOverscanFrame.right, 0),
- Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
+ mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+ Math.max(mOverscanFrame.top - frame.top, 0),
+ Math.max(frame.right - mOverscanFrame.right, 0),
+ Math.max(frame.bottom - mOverscanFrame.bottom, 0));
- mContentInsets.set(mContentFrame.left - mFrame.left,
- mContentFrame.top - mFrame.top,
- mFrame.right - mContentFrame.right,
- mFrame.bottom - mContentFrame.bottom);
+ mContentInsets.set(mContentFrame.left - frame.left,
+ mContentFrame.top - frame.top,
+ frame.right - mContentFrame.right,
+ frame.bottom - mContentFrame.bottom);
- mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
- mVisibleFrame.top - mFrame.top,
- mFrame.right - mVisibleFrame.right,
- mFrame.bottom - mVisibleFrame.bottom);
+ mVisibleInsets.set(mVisibleFrame.left - frame.left,
+ mVisibleFrame.top - frame.top,
+ frame.right - mVisibleFrame.right,
+ frame.bottom - mVisibleFrame.bottom);
- mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
- Math.max(mStableFrame.top - mFrame.top, 0),
- Math.max(mFrame.right - mStableFrame.right, 0),
- Math.max(mFrame.bottom - mStableFrame.bottom, 0));
+ if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+ // For the docked divider, we calculate the stable insets like a full-screen window
+ // so it can use it to calculate the snap positions.
+ mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
+ Math.max(mStableFrame.top - mDisplayFrame.top, 0),
+ Math.max(mDisplayFrame.right - mStableFrame.right, 0),
+ Math.max(mDisplayFrame.bottom - mStableFrame.bottom, 0));
+ } else {
+ mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
+ Math.max(mStableFrame.top - frame.top, 0),
+ Math.max(frame.right - mStableFrame.right, 0),
+ Math.max(frame.bottom - mStableFrame.bottom, 0));
+ }
+
+ if (!mInsetFrame.isEmpty()) {
+ mContentFrame.set(mFrame);
+ mContentFrame.top += mContentInsets.top;
+ mContentFrame.bottom += mContentInsets.bottom;
+ mContentFrame.left += mContentInsets.left;
+ mContentFrame.right += mContentInsets.right;
+ mVisibleFrame.set(mFrame);
+ mVisibleFrame.top += mVisibleInsets.top;
+ mVisibleFrame.bottom += mVisibleInsets.bottom;
+ mVisibleFrame.left += mVisibleInsets.left;
+ mVisibleFrame.right += mVisibleInsets.right;
+ mStableFrame.set(mFrame);
+ mStableFrame.top += mStableInsets.top;
+ mStableFrame.bottom += mStableInsets.bottom;
+ mStableFrame.left += mStableInsets.left;
+ mStableFrame.right += mStableInsets.right;
+ }
mCompatFrame.set(mFrame);
if (mEnforceSizeCompat) {
// If there is a size compatibility scale being applied to the
@@ -1204,9 +1259,9 @@
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
boolean hasMoved() {
- return mHasSurface && mContentChanged && !mExiting && !mWinAnimator.mLastHidden
- && mService.okToDisplay() && (mFrame.top != mLastFrame.top
- || mFrame.left != mLastFrame.left)
+ return mHasSurface && (mContentChanged || mMovedByResize)
+ && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+ && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
&& (mAttachedWindow == null || !mAttachedWindow.hasMoved());
}
@@ -1273,6 +1328,29 @@
mHasSurface = hasSurface;
}
+ int getAnimLayerAdjustment() {
+ if (mTargetAppToken != null) {
+ return mTargetAppToken.mAppAnimator.animLayerAdjustment;
+ } else if (mAppToken != null) {
+ return mAppToken.mAppAnimator.animLayerAdjustment;
+ } else {
+ // Nothing is animating, so there is no animation adjustment.
+ return 0;
+ }
+ }
+
+ void scheduleAnimationIfDimming() {
+ if (mDisplayContent == null) {
+ return;
+ }
+ final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+ if (dimLayerUser != null && mDisplayContent.mDimLayerController.isDimming(
+ dimLayerUser, mWinAnimator)) {
+ // Force an animation pass just to update the mDimLayer layer.
+ mService.scheduleAnimationLocked();
+ }
+ }
+
private final class DeadWindowEventReceiver extends InputEventReceiver {
DeadWindowEventReceiver(InputChannel inputChannel) {
super(inputChannel, mService.mH.getLooper());
@@ -1529,12 +1607,7 @@
return isVisibleOrAdding()
&& (mViewVisibility == View.VISIBLE)
&& ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
- && stackCanReceiveKeys();
- }
-
- boolean stackCanReceiveKeys() {
- final TaskStack stack = getStack();
- return stack != null && StackId.canReceiveKeys(stack.mStackId);
+ && (mAppToken == null || mAppToken.windowsAreFocusable());
}
@Override
@@ -1926,8 +1999,8 @@
// isDragResizing() or isDragResizeChanged() is true.
boolean resizing = isDragResizing() || isDragResizeChanged();
final Rect backDropFrame = (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
- mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
- outsets, reportDraw, newConfig, backDropFrame);
+ mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+ reportDraw, newConfig, backDropFrame);
}
public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -1974,7 +2047,13 @@
if (task.isDragResizing()) {
return true;
}
- return mDisplayContent.mDividerControllerLocked.isResizing() &&
+
+ // If the bounds are currently frozen, it means that the layout size that the app sees
+ // and the bounds we clip this window to might be different. In order to avoid holes, we
+ // simulate that we are still resizing so the app fills the hole with the resizing
+ // background.
+ return (mDisplayContent.mDividerControllerLocked.isResizing()
+ || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
!task.inFreeformWorkspace() && !task.isFullscreen();
}
@@ -2253,7 +2332,7 @@
}
if (nonFullscreenTask) {
- // Make sure window fits in containing frame since it is in a non-fullscreen stack as
+ // Make sure window fits in containing frame since it is in a non-fullscreen task as
// required by {@link Gravity#apply} call.
w = Math.min(w, pw);
h = Math.min(h, ph);
@@ -2273,10 +2352,21 @@
}
void setReplacing(boolean animate) {
- if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) == 0) {
- mWillReplaceWindow = true;
- mReplacingWindow = null;
- mAnimateReplacingWindow = animate;
+ if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
+ || mAttrs.type == TYPE_APPLICATION_STARTING) {
+ // We don't set replacing on starting windows since they are added by window manager and
+ // not the client so won't be replaced by the client.
+ return;
}
+
+ mWillReplaceWindow = true;
+ mReplacingWindow = null;
+ mAnimateReplacingWindow = animate;
+ }
+
+ void resetReplacing() {
+ mWillReplaceWindow = false;
+ mReplacingWindow = null;
+ mAnimateReplacingWindow = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d4001cd..83ab190 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -37,6 +37,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
import static com.android.server.wm.WindowManagerService.localLOGV;
+import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -384,12 +385,8 @@
if (mAnimator.mWindowDetachedWallpaper == mWin) {
mAnimator.mWindowDetachedWallpaper = null;
}
- mAnimLayer = mWin.mLayer;
- if (mWin.mIsImWindow) {
- mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
- } else if (mIsWallpaper) {
- mAnimLayer += mWallpaperControllerLocked.getAnimLayerAdjustment();
- }
+ mAnimLayer = mWin.mLayer
+ + mService.mLayersController.getSpecialWindowAnimLayerAdjustment(mWin);
if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
mHasTransformation = false;
mHasLocalTransformation = false;
@@ -709,14 +706,12 @@
}
// Something is wrong and SurfaceFlinger will not like this, try to revert to sane values.
+ // This doesn't necessarily mean that there is an error in the system. The sizes might be
+ // incorrect, because it is before the first layout or draw.
if (mTmpSize.width() < 1) {
- if (!mWin.mLayoutNeeded) Slog.w(TAG,
- "Width of " + w + " is not positive " + mTmpSize.width());
mTmpSize.right = mTmpSize.left + 1;
}
if (mTmpSize.height() < 1) {
- if (!mWin.mLayoutNeeded) Slog.w(TAG,
- "Height of " + w + " is not positive " + mTmpSize.height());
mTmpSize.bottom = mTmpSize.top + 1;
}
@@ -1069,7 +1064,16 @@
final int top = w.mYOffset + w.mFrame.top;
// Initialize the decor rect to the entire frame.
- mSystemDecorRect.set(0, 0, width, height);
+ if (w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) {
+
+ // If we are resizing with the divider, the task bounds might be smaller than the
+ // stack bounds. The system decor is used to clip to the task bounds, which we don't
+ // want in this case in order to avoid holes.
+ final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+ mSystemDecorRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+ } else {
+ mSystemDecorRect.set(0, 0, width, height);
+ }
// If a freeform window is animating from a position where it would be cutoff, it would be
// cutoff during the animation. We don't want that, so for the duration of the animation
@@ -1188,11 +1192,14 @@
// We don't apply the stack bounds crop if:
// 1. The window is currently animating docked mode or in freeform mode, otherwise the
// animating window will be suddenly (docked) or for whole animation (freeform) cut off.
+ // (Note that we still need to apply the crop if the task being docked is non-resizeable,
+ // in which case the task is running in fullscreen size but cropped to stack bounds.)
// 2. The window that is being replaced during animation, because it was living in a
// different stack. If we suddenly crop it to the new stack bounds, it might get cut off.
// We don't want it to happen, so we let it ignore the stack bounds until it gets removed.
// The window that will replace it will abide them.
- if (isAnimating() && (w.mWillReplaceWindow || w.inDockedWorkspace()
+ if (isAnimating() && (w.mWillReplaceWindow
+ || (w.inDockedWorkspace() && task.isResizeable())
|| w.inFreeformWorkspace())) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 160c97f..feeab27 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -524,7 +524,7 @@
}
for (DisplayContent displayContent : displayList) {
- mService.assignLayersLocked(displayContent.getWindowList());
+ mService.mLayersController.assignLayersLocked(displayContent.getWindowList());
displayContent.layoutNeeded = true;
}
}
@@ -599,7 +599,7 @@
if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
mWallpaperControllerLocked.adjustWallpaperWindows()) {
- mService.assignLayersLocked(windows);
+ mService.mLayersController.assignLayersLocked(windows);
displayContent.layoutNeeded = true;
}
@@ -709,6 +709,7 @@
//Slog.i(TAG_WM, "Window " + this + " clearing mContentChanged - done placing");
w.mContentChanged = false;
+ w.mMovedByResize = false;
// Moved from updateWindowsAndWallpaperLocked().
if (w.mHasSurface) {
@@ -738,13 +739,15 @@
}
}
}
- /*
- * Updates the shown frame before we set up the surface. This is needed because
- * the resizing could change the top-left position (in addition to size) of the
- * window. setSurfaceBoundariesLocked uses mShownPosition to position the
- * surface.
- */
- winAnimator.computeShownFrameLocked();
+ if (!winAnimator.isAnimating()) {
+ // Updates the shown frame before we set up the surface. This is needed
+ // because the resizing could change the top-left position (in addition to
+ // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
+ // position the surface. We only apply it to windows that aren't animating,
+ // because we depend on the animation to calculate the correct shown frame
+ // on the next animation step.
+ winAnimator.computeShownFrameLocked();
+ }
winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
}
@@ -1134,7 +1137,7 @@
// TODO(multidisplay): IMEs are only supported on the default display.
if (windows == mService.getDefaultWindowListLocked()
&& !mService.moveInputMethodWindowsIfNeededLocked(true)) {
- mService.assignLayersLocked(windows);
+ mService.mLayersController.assignLayersLocked(windows);
}
mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
true /*updateInputWindows*/);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 4c8474a..a5237ca 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -207,6 +207,7 @@
void setPointerIconShape(int32_t iconId);
void reloadPointerIcons();
void setCustomPointerIcon(const SpriteIcon& icon);
+ void setPointerIconDetached(bool detached);
/* --- InputReaderPolicyInterface implementation --- */
@@ -711,6 +712,14 @@
mInputManager->getDispatcher()->setFocusedApplication(applicationHandle);
}
+void NativeInputManager::setPointerIconDetached(bool detached) {
+ AutoMutex _l(mLock);
+ sp<PointerController> controller = mLocked.pointerController.promote();
+ if (controller != NULL) {
+ controller->detachPointerIcon(detached);
+ }
+}
+
void NativeInputManager::setInputDispatchMode(bool enabled, bool frozen) {
mInputManager->getDispatcher()->setInputDispatchMode(enabled, frozen);
}
@@ -1317,6 +1326,12 @@
im->setFocusedApplication(env, applicationHandleObj);
}
+static void nativeSetPointerIconDetached(JNIEnv* env, jclass /* clazz */, jlong ptr,
+ jboolean detached) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ im->setPointerIconDetached(detached);
+}
+
static void nativeSetInputDispatchMode(JNIEnv* /* env */,
jclass /* clazz */, jlong ptr, jboolean enabled, jboolean frozen) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1497,6 +1512,8 @@
(void*) nativeSetInputWindows },
{ "nativeSetFocusedApplication", "(JLcom/android/server/input/InputApplicationHandle;)V",
(void*) nativeSetFocusedApplication },
+ { "nativeSetPointerIconDetached", "(JZ)V",
+ (void*) nativeSetPointerIconDetached },
{ "nativeSetInputDispatchMode", "(JZZ)V",
(void*) nativeSetInputDispatchMode },
{ "nativeSetSystemUiVisibility", "(JI)V",
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 01acdef..6c640ba 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -54,6 +54,7 @@
jmethodID maxWidth;
jmethodID maxHeight;
jmethodID generation;
+ jmethodID flags;
jmethodID build;
} gTvStreamConfigBuilderClassInfo;
@@ -239,7 +240,7 @@
int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
int removeStream(int deviceId, int streamId);
- const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
+ const tv_stream_config_ext_t* getStreamConfigs(int deviceId, int* numConfigs);
void onDeviceAvailable(const tv_input_device_info_t& info);
void onDeviceUnavailable(int deviceId);
@@ -288,10 +289,15 @@
sp<Looper> mLooper;
KeyedVector<int, KeyedVector<int, Connection> > mConnections;
+
+ tv_stream_config_ext_t* mConfigBuffer;
+ int mConfigBufferSize;
};
JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device,
- const sp<Looper>& looper) {
+ const sp<Looper>& looper)
+ : mConfigBuffer(NULL),
+ mConfigBufferSize(0) {
mThiz = env->NewWeakGlobalRef(thiz);
mDevice = device;
mCallback.notify = &JTvInputHal::notify;
@@ -306,6 +312,10 @@
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(mThiz);
mThiz = NULL;
+
+ if (mConfigBuffer != NULL) {
+ delete[] mConfigBuffer;
+ }
}
JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
@@ -354,15 +364,14 @@
if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
// Need to configure stream
int numConfigs = 0;
- const tv_stream_config_t* configs = NULL;
- if (mDevice->get_stream_configurations(
- mDevice, deviceId, &numConfigs, &configs) != 0) {
+ const tv_stream_config_ext_t* configs = getStreamConfigs(deviceId, &numConfigs);
+ if (configs == NULL) {
ALOGE("Couldn't get stream configs");
return UNKNOWN_ERROR;
}
int configIndex = -1;
for (int i = 0; i < numConfigs; ++i) {
- if (configs[i].stream_id == streamId) {
+ if (configs[i].config.stream_id == streamId) {
configIndex = i;
break;
}
@@ -371,13 +380,13 @@
ALOGE("Cannot find a config with given stream ID: %d", streamId);
return BAD_VALUE;
}
- connection.mStreamType = configs[configIndex].type;
+ connection.mStreamType = configs[configIndex].config.type;
tv_stream_t stream;
- stream.stream_id = configs[configIndex].stream_id;
+ stream.stream_id = configs[configIndex].config.stream_id;
if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) {
- stream.buffer_producer.width = configs[configIndex].max_video_width;
- stream.buffer_producer.height = configs[configIndex].max_video_height;
+ stream.buffer_producer.width = configs[configIndex].config.max_video_width;
+ stream.buffer_producer.height = configs[configIndex].config.max_video_height;
}
if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) {
ALOGE("Couldn't add stream");
@@ -431,12 +440,33 @@
return NO_ERROR;
}
-const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
- const tv_stream_config_t* configs = NULL;
- if (mDevice->get_stream_configurations(
- mDevice, deviceId, numConfigs, &configs) != 0) {
- ALOGE("Couldn't get stream configs");
- return NULL;
+const tv_stream_config_ext_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
+ const tv_stream_config_ext_t* configs = NULL;
+ if (mDevice->common.version >= TV_INPUT_DEVICE_API_VERSION_0_2) {
+ if (mDevice->get_stream_configurations_ext(
+ mDevice, deviceId, numConfigs, &configs) != 0) {
+ ALOGE("Couldn't get stream configs");
+ return NULL;
+ }
+ } else {
+ const tv_stream_config_t* oldConfigs;
+ if (mDevice->get_stream_configurations(
+ mDevice, deviceId, numConfigs, &oldConfigs) != 0) {
+ ALOGE("Couldn't get stream configs");
+ return NULL;
+ }
+ if (mConfigBufferSize < *numConfigs) {
+ mConfigBufferSize = (*numConfigs / 16 + 1) * 16;
+ if (mConfigBuffer != NULL) {
+ delete[] mConfigBuffer;
+ }
+ mConfigBuffer = new tv_stream_config_ext_t[mConfigBufferSize];
+ }
+ for (int i = 0; i < *numConfigs; ++i) {
+ mConfigBuffer[i].config = oldConfigs[i];
+ mConfigBuffer[i].flags = 0;
+ }
+ configs = mConfigBuffer;
}
return configs;
}
@@ -629,7 +659,7 @@
jlong ptr, jint deviceId, jint generation) {
JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
int numConfigs = 0;
- const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
+ const tv_stream_config_ext_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs);
jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL);
for (int i = 0; i < numConfigs; ++i) {
@@ -637,15 +667,20 @@
gTvStreamConfigBuilderClassInfo.clazz,
gTvStreamConfigBuilderClassInfo.constructor);
env->CallObjectMethod(
- builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id);
+ builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].config.stream_id);
env->CallObjectMethod(
- builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type);
+ builder, gTvStreamConfigBuilderClassInfo.type, configs[i].config.type);
env->CallObjectMethod(
- builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width);
+ builder, gTvStreamConfigBuilderClassInfo.maxWidth,
+ configs[i].config.max_video_width);
env->CallObjectMethod(
- builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height);
+ builder, gTvStreamConfigBuilderClassInfo.maxHeight,
+ configs[i].config.max_video_height);
env->CallObjectMethod(
builder, gTvStreamConfigBuilderClassInfo.generation, generation);
+ env->CallObjectMethod(
+ builder, gTvStreamConfigBuilderClassInfo.flags,
+ configs[i].flags);
jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build);
@@ -737,6 +772,10 @@
gTvStreamConfigBuilderClassInfo.clazz,
"generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
GET_METHOD_ID(
+ gTvStreamConfigBuilderClassInfo.flags,
+ gTvStreamConfigBuilderClassInfo.clazz,
+ "flags", "(I)Landroid/media/tv/TvStreamConfig$Builder;");
+ GET_METHOD_ID(
gTvStreamConfigBuilderClassInfo.build,
gTvStreamConfigBuilderClassInfo.clazz,
"build", "()Landroid/media/tv/TvStreamConfig;");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c540e05..dd58b3c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16,8 +16,6 @@
package com.android.server.devicepolicy;
-import com.google.android.collect.Sets;
-
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -28,6 +26,8 @@
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.TEXT;
+import com.google.android.collect.Sets;
+
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
@@ -129,6 +129,7 @@
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserRestrictionsUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -193,6 +194,8 @@
private static final String ATTR_PERMISSION_POLICY = "permission-policy";
private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
+ private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
+ = "application-restrictions-manager";
private static final int STATUS_BAR_DISABLE_MASK =
StatusBarManager.DISABLE_EXPAND |
@@ -322,6 +325,8 @@
boolean doNotAskCredentialsOnBoot = false;
+ String mApplicationRestrictionsManagingPackage;
+
public DevicePolicyData(int userHandle) {
mUserHandle = userHandle;
}
@@ -420,6 +425,9 @@
private static final String TAG_PACKAGE_LIST_ITEM = "item";
private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages";
private static final String TAG_USER_RESTRICTIONS = "user-restrictions";
+ private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message";
+ private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
+ private static final String TAG_PARENT_ADMIN = "parent-admin";
final DeviceAdminInfo info;
@@ -472,6 +480,9 @@
boolean disableScreenCapture = false; // Can only be set by a device/profile owner.
boolean requireAutoTime = false; // Can only be set by a device owner.
+ ActiveAdmin parentAdmin;
+ final boolean isParent;
+
static class TrustAgentInfo {
public PersistableBundle options;
TrustAgentInfo(PersistableBundle bundle) {
@@ -505,8 +516,20 @@
Bundle userRestrictions;
- ActiveAdmin(DeviceAdminInfo _info) {
+ // Support text provided by the admin to display to the user.
+ String shortSupportMessage = null;
+ String longSupportMessage = null;
+
+ ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
info = _info;
+ isParent = parent;
+ }
+
+ ActiveAdmin getParentActiveAdmin() {
+ if (parentAdmin == null && !isParent) {
+ parentAdmin = new ActiveAdmin(info, /* parent */ true);
+ }
+ return parentAdmin;
}
int getUid() { return info.getActivityInfo().applicationInfo.uid; }
@@ -684,6 +707,21 @@
UserRestrictionsUtils.writeRestrictions(
out, userRestrictions, TAG_USER_RESTRICTIONS);
}
+ if (!TextUtils.isEmpty(shortSupportMessage)) {
+ out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+ out.text(shortSupportMessage);
+ out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+ }
+ if (!TextUtils.isEmpty(longSupportMessage)) {
+ out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
+ out.text(longSupportMessage);
+ out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
+ }
+ if (parentAdmin != null) {
+ out.startTag(null, TAG_PARENT_ADMIN);
+ parentAdmin.writeToXml(out);
+ out.endTag(null, TAG_PARENT_ADMIN);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -797,6 +835,23 @@
keepUninstalledPackages = readPackageList(parser, tag);
} else if (TAG_USER_RESTRICTIONS.equals(tag)) {
UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+ } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ shortSupportMessage = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading short support message");
+ }
+ } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ longSupportMessage = parser.getText();
+ } else {
+ Log.w(LOG_TAG, "Missing text when loading long support message");
+ }
+ } else if (TAG_PARENT_ADMIN.equals(tag)) {
+ parentAdmin = new ActiveAdmin(info, /* parent */ true);
+ parentAdmin.readFromXml(parser);
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1035,19 +1090,15 @@
saveSettingsLocked(policy.mUserHandle);
}
- if (policy.mDelegatedCertInstallerPackage != null &&
- (packageName == null
- || packageName.equals(policy.mDelegatedCertInstallerPackage))) {
- try {
- // Check if delegated cert installer package is removed.
- if (mIPackageManager.getPackageInfo(
- policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) {
- policy.mDelegatedCertInstallerPackage = null;
- saveSettingsLocked(policy.mUserHandle);
- }
- } catch (RemoteException e) {
- // Shouldn't happen
- }
+ // Check if delegated cert installer or app restrictions managing packages are removed.
+ if (isRemovedPackage(packageName, policy.mDelegatedCertInstallerPackage, userHandle)) {
+ policy.mDelegatedCertInstallerPackage = null;
+ saveSettingsLocked(policy.mUserHandle);
+ }
+ if (isRemovedPackage(
+ packageName, policy.mApplicationRestrictionsManagingPackage, userHandle)) {
+ policy.mApplicationRestrictionsManagingPackage = null;
+ saveSettingsLocked(policy.mUserHandle);
}
}
if (removed) {
@@ -1056,6 +1107,18 @@
}
}
+ private boolean isRemovedPackage(String changedPackage, String targetPackage, int userHandle) {
+ try {
+ return targetPackage != null
+ && (changedPackage == null || changedPackage.equals(targetPackage))
+ && mIPackageManager.getPackageInfo(targetPackage, 0, userHandle) == null;
+ } catch (RemoteException e) {
+ // Shouldn't happen
+ }
+
+ return false;
+ }
+
/**
* Unit test will subclass it to inject mocks.
*/
@@ -1162,6 +1225,10 @@
mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
}
+ void powerManagerReboot(String reason) {
+ mContext.getSystemService(PowerManager.class).reboot(reason);
+ }
+
boolean systemPropertiesGetBoolean(String key, boolean def) {
return SystemProperties.getBoolean(key, def);
}
@@ -1583,6 +1650,23 @@
}
}
+ /**
+ * Find the admin for the component and userId bit of the uid, then check
+ * the admin's uid matches the uid.
+ */
+ private ActiveAdmin getActiveAdminForUidLocked(ComponentName who, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ final DevicePolicyData policy = getUserData(userId);
+ ActiveAdmin admin = policy.mAdminMap.get(who);
+ if (admin == null) {
+ throw new SecurityException("No active admin " + who);
+ }
+ if (admin.getUid() != uid) {
+ throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
+ }
+ return admin;
+ }
+
private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
int uid) {
// Try to find an admin which can use reqPolicy
@@ -1594,8 +1678,7 @@
throw new SecurityException("No active admin " + who);
}
if (admin.getUid() != uid) {
- throw new SecurityException("Admin " + who + " is not owned by uid "
- + mInjector.binderGetCallingUid());
+ throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
}
if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
return admin;
@@ -1728,7 +1811,7 @@
enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
- List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
+ List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser(
resolveIntent,
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
userHandle);
@@ -1795,6 +1878,10 @@
out.attribute(null, ATTR_DELEGATED_CERT_INSTALLER,
policy.mDelegatedCertInstallerPackage);
}
+ if (policy.mApplicationRestrictionsManagingPackage != null) {
+ out.attribute(null, ATTR_APPLICATION_RESTRICTIONS_MANAGER,
+ policy.mApplicationRestrictionsManagingPackage);
+ }
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
@@ -1920,6 +2007,8 @@
}
policy.mDelegatedCertInstallerPackage = parser.getAttributeValue(null,
ATTR_DELEGATED_CERT_INSTALLER);
+ policy.mApplicationRestrictionsManagingPackage = parser.getAttributeValue(null,
+ ATTR_APPLICATION_RESTRICTIONS_MANAGER);
type = parser.next();
int outerDepth = parser.getDepth();
@@ -1946,7 +2035,7 @@
+ userHandle);
}
if (dai != null) {
- ActiveAdmin ap = new ActiveAdmin(dai);
+ ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false);
ap.readFromXml(parser);
policy.mAdminMap.put(ap.info.getComponent(), ap);
}
@@ -2337,7 +2426,7 @@
&& getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
- ActiveAdmin newAdmin = new ActiveAdmin(info);
+ ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);
policy.mAdminMap.put(adminReceiver, newAdmin);
int replaceIndex = -1;
final int N = policy.mAdminList.size();
@@ -2472,8 +2561,14 @@
}
}
+ private boolean isAdminApiLevelPreN(@NonNull ComponentName who, int userHandle) {
+ DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false);
+ return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion
+ < Build.VERSION_CODES.N;
+ }
+
@Override
- public void setPasswordQuality(ComponentName who, int quality) {
+ public void setPasswordQuality(ComponentName who, int quality, boolean parent) {
if (!mHasFeature) {
return;
}
@@ -2484,6 +2579,9 @@
synchronized (this) {
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ if (parent) {
+ ap = ap.getParentActiveAdmin();
+ }
if (ap.passwordQuality != quality) {
ap.passwordQuality = quality;
saveSettingsLocked(userHandle);
@@ -2492,7 +2590,7 @@
}
@Override
- public int getPasswordQuality(ComponentName who, int userHandle) {
+ public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) {
if (!mHasFeature) {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
}
@@ -2502,20 +2600,43 @@
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (parent && admin != null) {
+ admin = admin.getParentActiveAdmin();
+ }
return admin != null ? admin.passwordQuality : mode;
}
- // Return strictest policy for this user and profiles that are visible from this user.
- List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
- for (UserInfo userInfo : profiles) {
- DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
+ if (LockPatternUtils.isSeparateWorkChallengeEnabled() && !parent) {
+ // If a Work Challenge is in use, only return its restrictions.
+ DevicePolicyData policy = getUserDataUnchecked(userHandle);
final int N = policy.mAdminList.size();
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (mode < admin.passwordQuality) {
mode = admin.passwordQuality;
}
}
+ } else {
+ // Return strictest policy for this user and profiles that are visible from this
+ // user that do not use a separate work challenge.
+ // TODO: When there are separate parent restrictions the profile should just
+ // obey its own.
+ List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+ for (UserInfo userInfo : profiles) {
+ // Only aggregate data for the parent profile plus the non-work challenge
+ // enabled profiles.
+ if (!(userInfo.isManagedProfile()
+ && LockPatternUtils.isSeparateWorkChallengeEnabled())) {
+ DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
+ final int N = policy.mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
+ if (mode < admin.passwordQuality) {
+ mode = admin.passwordQuality;
+ }
+ }
+ }
+ }
}
return mode;
}
@@ -3075,7 +3196,7 @@
}
@Override
- public boolean isActivePasswordSufficient(int userHandle) {
+ public boolean isActivePasswordSufficient(int userHandle, boolean parent) {
if (!mHasFeature) {
return true;
}
@@ -3087,8 +3208,14 @@
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
- if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
+ ActiveAdmin admin =
+ getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
+ ComponentName adminComponentName = admin.info.getComponent();
+ // TODO: Include the Admin sdk level check in LockPatternUtils check.
+ ComponentName who = !isAdminApiLevelPreN(adminComponentName, userHandle)
+ && LockPatternUtils.isSeparateWorkChallengeEnabled()
+ ? adminComponentName : null;
+ if (policy.mActivePasswordQuality < getPasswordQuality(who, userHandle, parent)
|| policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
return false;
}
@@ -3253,7 +3380,7 @@
}
}
}
- quality = getPasswordQuality(null, userHandle);
+ quality = getPasswordQuality(null, userHandle, false);
if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int realQuality = LockPatternUtils.computePasswordQuality(password);
if (realQuality < quality
@@ -3550,7 +3677,7 @@
}
try {
- int uid = mContext.getPackageManager().getPackageUid(
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
policy.mDelegatedCertInstallerPackage, userHandle);
return uid == callingUid;
} catch (NameNotFoundException e) {
@@ -3681,7 +3808,7 @@
public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
final IBinder response) {
// Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
- if (UserHandle.getAppId(mInjector.binderGetCallingUid()) != Process.SYSTEM_UID) {
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
return;
}
@@ -4710,7 +4837,7 @@
Preconditions.checkNotNull(packageName, "packageName is null");
final int callingUid = mInjector.binderGetCallingUid();
try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+ int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
if (uid != callingUid) {
throw new SecurityException("Invalid packageName");
}
@@ -4815,6 +4942,7 @@
DevicePolicyData policy = getUserData(userId);
policy.mPermissionPolicy = DevicePolicyManager.PERMISSION_POLICY_PROMPT;
policy.mDelegatedCertInstallerPackage = null;
+ policy.mApplicationRestrictionsManagingPackage = null;
policy.mStatusBarDisabled = false;
saveSettingsLocked(userId);
@@ -4991,7 +5119,7 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
if (hasUserSetupCompleted(userHandle)
- && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
+ && !UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)) {
throw new IllegalStateException("Cannot set the profile owner on a user which is "
+ "already set-up");
}
@@ -5051,7 +5179,8 @@
private void enforceManageUsers() {
final int callingUid = mInjector.binderGetCallingUid();
- if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
+ if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || callingUid == Process.ROOT_UID)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
}
}
@@ -5062,7 +5191,8 @@
}
final int callingUid = mInjector.binderGetCallingUid();
if (userHandle == UserHandle.getUserId(callingUid)) return;
- if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID) || callingUid == 0)) {
+ if (!(UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+ || callingUid == Process.ROOT_UID)) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
+ " INTERACT_ACROSS_USERS_FULL permission");
@@ -5185,18 +5315,68 @@
}
@Override
- public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+ public void setApplicationRestrictionsManagingPackage(ComponentName admin, String packageName) {
+ final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ DevicePolicyData policy = getUserData(userHandle);
+ policy.mApplicationRestrictionsManagingPackage = packageName;
+ saveSettingsLocked(userHandle);
+ }
+ }
- long id = mInjector.binderClearCallingIdentity();
- try {
- mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ @Override
+ public String getApplicationRestrictionsManagingPackage(ComponentName admin) {
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ DevicePolicyData policy = getUserData(userHandle);
+ return policy.mApplicationRestrictionsManagingPackage;
+ }
+ }
+
+ @Override
+ public boolean isCallerApplicationRestrictionsManagingPackage() {
+ final int callingUid = mInjector.binderGetCallingUid();
+ final int userHandle = UserHandle.getUserId(callingUid);
+ synchronized (this) {
+ final DevicePolicyData policy = getUserData(userHandle);
+ if (policy.mApplicationRestrictionsManagingPackage == null) {
+ return false;
}
+
+ try {
+ int uid = mContext.getPackageManager().getPackageUidAsUser(
+ policy.mApplicationRestrictionsManagingPackage, userHandle);
+ return uid == callingUid;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+ }
+ }
+
+ private void enforceCanManageApplicationRestrictions(ComponentName who) {
+ if (who != null) {
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+ } else if (!isCallerApplicationRestrictionsManagingPackage()) {
+ throw new SecurityException(
+ "No admin component given, and caller cannot manage application restrictions "
+ + "for other apps.");
+ }
+ }
+
+ @Override
+ public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
+ enforceCanManageApplicationRestrictions(who);
+
+ final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
}
}
@@ -5292,7 +5472,7 @@
@Override
public ComponentName getRestrictionsProvider(int userHandle) {
synchronized (this) {
- if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
throw new SecurityException("Only the system can query the permission provider");
}
DevicePolicyData userData = getUserData(userHandle);
@@ -5762,21 +5942,62 @@
@Override
public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
- Preconditions.checkNotNull(who, "ComponentName is null");
- final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
+ enforceCanManageApplicationRestrictions(who);
+ final UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
+ // if no restrictions were saved, mUserManager.getApplicationRestrictions
+ // returns null, but DPM method should return an empty Bundle as per JavaDoc
+ return bundle != null ? bundle : Bundle.EMPTY;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+ @Override
+ public boolean setPackageSuspended(ComponentName who, String packageName,
+ boolean suspended) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ int callingUserId = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long id = mInjector.binderClearCallingIdentity();
try {
- Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
- // if no restrictions were saved, mUserManager.getApplicationRestrictions
- // returns null, but DPM method should return an empty Bundle as per JavaDoc
- return bundle != null ? bundle : Bundle.EMPTY;
+ return mIPackageManager.setPackageSuspendedAsUser(
+ packageName, suspended, callingUserId);
+ } catch (RemoteException re) {
+ // Shouldn't happen.
+ Slog.e(LOG_TAG, "Failed talking to the package manager", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
+ return false;
+ }
+ }
+
+ @Override
+ public boolean getPackageSuspended(ComponentName who, String packageName) {
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ int callingUserId = UserHandle.getCallingUserId();
+ synchronized (this) {
+ getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+
+ long id = mInjector.binderClearCallingIdentity();
+ try {
+ ApplicationInfo appInfo = mIPackageManager.getApplicationInfo(
+ packageName, 0, callingUserId);
+ return appInfo != null &&
+ (appInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+ } catch (RemoteException re) {
+ // Shouldn't happen.
+ Slog.e(LOG_TAG, "Failed talking to the package manager", re);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ return false;
}
}
@@ -5855,7 +6076,9 @@
}
if (activeAdmin.getUid() != mInjector.binderGetCallingUid()) {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS,
+ "Calling uid " + mInjector.binderGetCallingUid() + " neither owns the admin"
+ + " " + who + " nor has MANAGE_PROFILE_AND_DEVICE_OWNERS permission");
}
return activeAdmin.userRestrictions;
}
@@ -6303,7 +6526,7 @@
@Override
public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
- if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
}
synchronized (this) {
@@ -6971,4 +7194,114 @@
return UserManager.isSplitSystemUser() && callingUserId == UserHandle.USER_SYSTEM;
}
+ @Override
+ public void reboot(ComponentName admin) {
+ Preconditions.checkNotNull(admin);
+ // Make sure caller has DO.
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ }
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
+ public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ if (!TextUtils.equals(admin.shortSupportMessage, message)) {
+ admin.shortSupportMessage = message;
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getShortSupportMessage(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ return admin.shortSupportMessage;
+ }
+ }
+
+ @Override
+ public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ final int userHandle = mInjector.userHandleGetCallingUserId();
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ if (!TextUtils.equals(admin.longSupportMessage, message)) {
+ admin.longSupportMessage = message;
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
+
+ @Override
+ public String getLongSupportMessage(@NonNull ComponentName who) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminForUidLocked(who,
+ mInjector.binderGetCallingUid());
+ return admin.longSupportMessage;
+ }
+ }
+
+ @Override
+ public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ throw new SecurityException("Only the system can query support message for user");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin != null) {
+ return admin.shortSupportMessage;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ Preconditions.checkNotNull(who, "ComponentName is null");
+ if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+ throw new SecurityException("Only the system can query support message for user");
+ }
+ synchronized (this) {
+ ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+ if (admin != null) {
+ return admin.longSupportMessage;
+ }
+ }
+ return null;
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 189ed33..dd6493c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -89,14 +89,13 @@
import com.android.server.tv.TvInputManagerService;
import com.android.server.twilight.TwilightService;
import com.android.server.usage.UsageStatsService;
-import com.android.server.usb.UsbService;
+import com.android.server.vr.VrManagerService;
import com.android.server.wallpaper.WallpaperManagerService;
import com.android.server.webkit.WebViewUpdateService;
import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;
-import java.io.File;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
@@ -141,6 +140,14 @@
"com.android.server.MountService$Lifecycle";
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
+ /**
+ * Default theme used by the system context. This is used to style
+ * system-provided dialogs, such as the Power Off dialog, and other
+ * visual content.
+ */
+ private static final int DEFAULT_SYSTEM_THEME =
+ com.android.internal.R.style.Theme_Material_DayNight_DarkActionBar;
+
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -320,7 +327,7 @@
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
- mSystemContext.setTheme(android.R.style.Theme_Material_DayNight_DarkActionBar);
+ mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
}
/**
@@ -439,6 +446,7 @@
ConsumerIrService consumerIr = null;
MmsServiceBroker mmsService = null;
EntropyMixer entropyMixer = null;
+ VrManagerService vrManagerService = null;
boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -524,6 +532,10 @@
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ traceBeginAndSlog("StartVrManagerService");
+ mSystemServiceManager.startService(VrManagerService.class);
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
mActivityManagerService.setWindowManager(wm);
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
@@ -1310,6 +1322,7 @@
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
+ intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 0a8c014..d250739 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -24,9 +24,9 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -55,7 +55,6 @@
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
-import java.util.Set;
/**
* SystemService wrapper for the PrintManager implementation. Publishes
@@ -77,8 +76,8 @@
}
@Override
- public void onStartUser(int userHandle) {
- mPrintManagerImpl.handleUserStarted(userHandle);
+ public void onUnlockUser(int userHandle) {
+ mPrintManagerImpl.handleUserUnlocked(userHandle);
}
@Override
@@ -87,11 +86,6 @@
}
class PrintManagerImpl extends IPrintManager.Stub {
- private static final char COMPONENT_NAME_SEPARATOR = ':';
-
- private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
- "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
-
private static final int BACKGROUND_USER_ID = -10;
private final Object mLock = new Object();
@@ -177,6 +171,25 @@
}
@Override
+ public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
+ final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
+ final UserState userState;
+ synchronized (mLock) {
+ // Only the current group members can get the printer icons.
+ if (resolveCallingProfileParentLocked(resolvedUserId) != getCurrentUserId()) {
+ return null;
+ }
+ userState = getOrCreateUserStateLocked(resolvedUserId);
+ }
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return userState.getCustomPrinterIcon(printerId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
@@ -467,20 +480,17 @@
private void registerContentObservers() {
final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
- Settings.Secure.ENABLED_PRINT_SERVICES);
+ Settings.Secure.DISABLED_PRINT_SERVICES);
ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) {
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
if (enabledPrintServicesUri.equals(uri)) {
synchronized (mLock) {
- if (userId != UserHandle.USER_ALL) {
- UserState userState = getOrCreateUserStateLocked(userId);
- userState.updateIfNeededLocked();
- } else {
- final int userCount = mUserStates.size();
- for (int i = 0; i < userCount; i++) {
- UserState userState = mUserStates.valueAt(i);
- userState.updateIfNeededLocked();
+ final int userCount = mUserStates.size();
+ for (int i = 0; i < userCount; i++) {
+ if (userId == UserHandle.USER_ALL
+ || userId == mUserStates.keyAt(i)) {
+ mUserStates.valueAt(i).updateIfNeededLocked();
}
}
}
@@ -494,19 +504,23 @@
private void registerBroadcastReceivers() {
PackageMonitor monitor = new PackageMonitor() {
- @Override
- public void onPackageModified(String packageName) {
+ private void updateServices(String packageName) {
+ if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
synchronized (mLock) {
// A background user/profile's print jobs are running but there is
// no UI shown. Hence, if the packages of such a user change we need
// to handle it as the change may affect ongoing print jobs.
boolean servicesChanged = false;
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
- Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
- while (iterator.hasNext()) {
- ComponentName componentName = iterator.next();
- if (packageName.equals(componentName.getPackageName())) {
+
+ List<PrintServiceInfo> installedServices = userState
+ .getInstalledPrintServices();
+ final int numInstalledServices = installedServices.size();
+ for (int i = 0; i < numInstalledServices; i++) {
+ if (installedServices.get(i).getResolveInfo().serviceInfo.packageName
+ .equals(packageName)) {
servicesChanged = true;
+ break;
}
}
if (servicesChanged) {
@@ -516,44 +530,31 @@
}
@Override
+ public void onPackageModified(String packageName) {
+ updateServices(packageName);
+ getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
+ }
+
+ @Override
public void onPackageRemoved(String packageName, int uid) {
- synchronized (mLock) {
- // A background user/profile's print jobs are running but there is
- // no UI shown. Hence, if the packages of such a user change we need
- // to handle it as the change may affect ongoing print jobs.
- boolean servicesRemoved = false;
- UserState userState = getOrCreateUserStateLocked(getChangingUserId());
- Iterator<ComponentName> iterator = userState.getEnabledServices().iterator();
- while (iterator.hasNext()) {
- ComponentName componentName = iterator.next();
- if (packageName.equals(componentName.getPackageName())) {
- userState.removeApprovedPrintService(componentName);
- iterator.remove();
- servicesRemoved = true;
- }
- }
- if (servicesRemoved) {
- persistComponentNamesToSettingLocked(
- Settings.Secure.ENABLED_PRINT_SERVICES,
- userState.getEnabledServices(), getChangingUserId());
- userState.updateIfNeededLocked();
- }
- }
+ updateServices(packageName);
+ getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices();
}
@Override
public boolean onHandleForceStop(Intent intent, String[] stoppedPackages,
int uid, boolean doit) {
+ if (!mUserManager.isUserUnlocked(getChangingUserId())) return false;
synchronized (mLock) {
// A background user/profile's print jobs are running but there is
// no UI shown. Hence, if the packages of such a user change we need
// to handle it as the change may affect ongoing print jobs.
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
boolean stoppedSomePackages = false;
- Iterator<ComponentName> iterator = userState.getEnabledServices()
+ Iterator<PrintServiceInfo> iterator = userState.getEnabledPrintServices()
.iterator();
while (iterator.hasNext()) {
- ComponentName componentName = iterator.next();
+ ComponentName componentName = iterator.next().getComponentName();
String componentPackage = componentName.getPackageName();
for (String stoppedPackage : stoppedPackages) {
if (componentPackage.equals(stoppedPackage)) {
@@ -574,6 +575,8 @@
@Override
public void onPackageAdded(String packageName, int uid) {
+ if (!mUserManager.isUserUnlocked(getChangingUserId())) return;
+
// A background user/profile's print jobs are running but there is
// no UI shown. Hence, if the packages of such a user change we need
// to handle it as the change may affect ongoing print jobs.
@@ -584,48 +587,11 @@
.queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES,
getChangingUserId());
- if (installedServices == null) {
- return;
- }
-
- // Enable all added services by default
- synchronized (mLock) {
+ if (installedServices != null) {
UserState userState = getOrCreateUserStateLocked(getChangingUserId());
-
- Set<ComponentName> enabledServices = userState.getEnabledServices();
- boolean servicesAdded = false;
-
- final int installedServiceCount = installedServices.size();
- for (int i = 0; i < installedServiceCount; i++) {
- ServiceInfo serviceInfo = installedServices.get(i).serviceInfo;
- ComponentName component = new ComponentName(serviceInfo.packageName,
- serviceInfo.name);
-
- enabledServices.add(component);
- servicesAdded = true;
- }
-
- if (servicesAdded) {
- persistComponentNamesToSettingLocked(
- Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices,
- getChangingUserId());
- userState.updateIfNeededLocked();
- }
+ userState.updateIfNeededLocked();
}
}
-
- private void persistComponentNamesToSettingLocked(String settingName,
- Set<ComponentName> componentNames, int userId) {
- StringBuilder builder = new StringBuilder();
- for (ComponentName componentName : componentNames) {
- if (builder.length() > 0) {
- builder.append(COMPONENT_NAME_SEPARATOR);
- }
- builder.append(componentName.flattenToShortString());
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- settingName, builder.toString(), userId);
- }
};
// package changes
@@ -634,6 +600,11 @@
}
private UserState getOrCreateUserStateLocked(int userId) {
+ if (!mUserManager.isUserUnlocked(userId)) {
+ throw new IllegalStateException(
+ "User " + userId + " must be unlocked for printing to be available");
+ }
+
UserState userState = mUserStates.get(userId);
if (userState == null) {
userState = new UserState(mContext, userId, mLock);
@@ -642,7 +613,7 @@
return userState;
}
- private void handleUserStarted(final int userId) {
+ private void handleUserUnlocked(final int userId) {
// This code will touch the remote print spooler which
// must be called off the main thread, so post the work.
BackgroundThread.getHandler().post(new Runnable() {
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 77a47f8..0af1525 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -24,6 +24,7 @@
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ParceledListSlice;
+import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -98,6 +99,15 @@
public void onPrintersAdded(List<PrinterInfo> printers);
public void onPrintersRemoved(List<PrinterId> printerIds);
public void onServiceDied(RemotePrintService service);
+
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon);
}
public RemotePrintService(Context context, ComponentName componentName, int userId,
@@ -404,6 +414,22 @@
printerId).sendToTarget();
}
+ /**
+ * Request the custom printer icon for a printer.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void requestCustomPrinterIcon(PrinterId printerId) {
+ try {
+ if (isBound()) {
+ mPrintService.requestCustomPrinterIcon(printerId);
+ }
+ } catch (RemoteException re) {
+ Slog.e(LOG_TAG, "Error requesting icon for " + printerId, re);
+ }
+ }
+
private void handleStartPrinterStateTracking(final PrinterId printerId) {
throwIfDestroyed();
// Take a note we are tracking the printer.
@@ -842,5 +868,19 @@
throw new IllegalArgumentException("Invalid printer id: " + printerId);
}
}
+
+ @Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon)
+ throws RemoteException {
+ RemotePrintService service = mWeakService.get();
+ if (service != null) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ service.mCallbacks.onCustomPrinterIconLoaded(printerId, icon);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
}
}
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index c506b6f..d179b95 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.graphics.drawable.Icon;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
@@ -35,17 +36,19 @@
import android.print.IPrintSpoolerClient;
import android.print.PrintJobId;
import android.print.PrintJobInfo;
+import android.print.PrinterId;
+import android.printservice.PrintService;
import android.util.Slog;
import android.util.TimedRemoteCaller;
+import libcore.io.IoUtils;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.concurrent.TimeoutException;
-import libcore.io.IoUtils;
-
/**
* This represents the remote print spooler as a local object to the
* PrintManagerService. It is responsible to connecting to the remote
@@ -72,6 +75,15 @@
private final SetPrintJobTagCaller mSetPrintJobTagCaller = new SetPrintJobTagCaller();
+ private final OnCustomPrinterIconLoadedCaller mCustomPrinterIconLoadedCaller =
+ new OnCustomPrinterIconLoadedCaller();
+
+ private final ClearCustomPrinterIconCacheCaller mClearCustomPrinterIconCache =
+ new ClearCustomPrinterIconCacheCaller();
+
+ private final GetCustomPrinterIconCaller mGetCustomPrinterIconCaller =
+ new GetCustomPrinterIconCaller();
+
private final ServiceConnection mServiceConnection = new MyServiceConnection();
private final Context mContext;
@@ -287,6 +299,96 @@
}
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @param icon the icon that was loaded
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public final void onCustomPrinterIconLoaded(@NonNull PrinterId printerId,
+ @Nullable Icon icon) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ mCustomPrinterIconLoadedCaller.onCustomPrinterIconLoaded(getRemoteInstanceLazy(),
+ printerId, icon);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error loading new custom printer icon.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier() + "] onCustomPrinterIconLoaded()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public final @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ return mGetCustomPrinterIconCaller.getCustomPrinterIcon(getRemoteInstanceLazy(),
+ printerId);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error getting custom printer icon.", re);
+ return null;
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier() + "] getCustomPrinterIcon()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Clear the custom printer icon cache
+ */
+ public void clearCustomPrinterIconCache() {
+ throwIfCalledOnMainThread();
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+ mCanUnbind = false;
+ }
+ try {
+ mClearCustomPrinterIconCache.clearCustomPrinterIconCache(getRemoteInstanceLazy());
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error clearing custom printer icon cache.", re);
+ } finally {
+ if (DEBUG) {
+ Slog.i(LOG_TAG,
+ "[user: " + mUserHandle.getIdentifier()
+ + "] clearCustomPrinterIconCache()");
+ }
+ synchronized (mLock) {
+ mCanUnbind = true;
+ mLock.notifyAll();
+ }
+ }
+ }
+
public final boolean setPrintJobTag(PrintJobId printJobId, String tag) {
throwIfCalledOnMainThread();
synchronized (mLock) {
@@ -338,26 +440,24 @@
}
/**
- * Connect to the print spooler service and remove an approved print service.
+ * Remove all approved {@link PrintService print services} that are not in the given set.
*
- * @param serviceToRemove The {@link ComponentName} of the service to be removed.
+ * @param servicesToKeep The {@link ComponentName names } of the services to keep
*/
- public final void removeApprovedPrintService(ComponentName serviceToRemove) {
+ public final void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
- getRemoteInstanceLazy().removeApprovedPrintService(serviceToRemove);
- } catch (RemoteException re) {
- Slog.e(LOG_TAG, "Error removing approved print service.", re);
- } catch (TimeoutException te) {
- Slog.e(LOG_TAG, "Error removing approved print service.", te);
+ getRemoteInstanceLazy().pruneApprovedPrintServices(servicesToKeep);
+ } catch (RemoteException|TimeoutException re) {
+ Slog.e(LOG_TAG, "Error pruning approved print services.", re);
} finally {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
- + "] removing approved print service()");
+ + "] pruneApprovedPrintServices()");
}
synchronized (mLock) {
mCanUnbind = true;
@@ -632,6 +732,69 @@
}
}
+ private static final class OnCustomPrinterIconLoadedCaller extends TimedRemoteCaller<Void> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public OnCustomPrinterIconLoadedCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onCustomPrinterIconCached(int sequence) {
+ onRemoteMethodResult(null, sequence);
+ }
+ };
+ }
+
+ public Void onCustomPrinterIconLoaded(IPrintSpooler target, PrinterId printerId,
+ Icon icon) throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.onCustomPrinterIconLoaded(printerId, icon, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class ClearCustomPrinterIconCacheCaller extends TimedRemoteCaller<Void> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public ClearCustomPrinterIconCacheCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void customPrinterIconCacheCleared(int sequence) {
+ onRemoteMethodResult(null, sequence);
+ }
+ };
+ }
+
+ public Void clearCustomPrinterIconCache(IPrintSpooler target)
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.clearCustomPrinterIconCache(mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
+ private static final class GetCustomPrinterIconCaller extends TimedRemoteCaller<Icon> {
+ private final IPrintSpoolerCallbacks mCallback;
+
+ public GetCustomPrinterIconCaller() {
+ super(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+ mCallback = new BasePrintSpoolerServiceCallbacks() {
+ @Override
+ public void onGetCustomPrinterIconResult(Icon icon, int sequence) {
+ onRemoteMethodResult(icon, sequence);
+ }
+ };
+ }
+
+ public Icon getCustomPrinterIcon(IPrintSpooler target, PrinterId printerId)
+ throws RemoteException, TimeoutException {
+ final int sequence = onBeforeRemoteCall();
+ target.getCustomPrinterIcon(printerId, mCallback, sequence);
+ return getResultTimed(sequence);
+ }
+ }
+
private static abstract class BasePrintSpoolerServiceCallbacks
extends IPrintSpoolerCallbacks.Stub {
@Override
@@ -658,6 +821,21 @@
public void onSetPrintJobTagResult(boolean success, int sequence) {
/* do nothing */
}
+
+ @Override
+ public void onCustomPrinterIconCached(int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void onGetCustomPrinterIconResult(@Nullable Icon icon, int sequence) {
+ /* do nothing */
+ }
+
+ @Override
+ public void customPrinterIconCacheCleared(int sequence) {
+ /* do nothing */
+ }
}
private static final class PrintSpoolerClient extends IPrintSpoolerClient.Stub {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 6a50a6e..dcc02a3 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -21,11 +21,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -97,7 +96,7 @@
private final List<PrintServiceInfo> mInstalledServices =
new ArrayList<PrintServiceInfo>();
- private final Set<ComponentName> mEnabledServices =
+ private final Set<ComponentName> mDisabledServices =
new ArraySet<ComponentName>();
private final PrintJobForAppCache mPrintJobForAppCache =
@@ -125,8 +124,15 @@
mLock = lock;
mSpooler = new RemotePrintSpooler(context, userId, this);
mHandler = new UserStateHandler(context.getMainLooper());
+
synchronized (mLock) {
- enableSystemPrintServicesLocked();
+ readInstalledPrintServicesLocked();
+ upgradePersistentStateIfNeeded();
+ readDisabledPrintServicesLocked();
+
+ // Some print services might have gotten installed before the User State came up
+ prunePrintServices();
+
onConfigurationChangedLocked();
}
}
@@ -271,6 +277,28 @@
return printJob;
}
+ /**
+ * Get the custom icon for a printer. If the icon is not cached, the icon is
+ * requested asynchronously. Once it is available the printer is updated.
+ *
+ * @param printerId the id of the printer the icon should be loaded for
+ * @return the custom icon to be used for the printer or null if the icon is
+ * not yet available
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public Icon getCustomPrinterIcon(PrinterId printerId) {
+ Icon icon = mSpooler.getCustomPrinterIcon(printerId);
+
+ if (icon == null) {
+ RemotePrintService service = mActiveServices.get(printerId.getServiceName());
+ if (service != null) {
+ service.requestCustomPrinterIcon(printerId);
+ }
+ }
+
+ return icon;
+ }
+
public void cancelPrintJob(PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
if (printJobInfo == null) {
@@ -297,15 +325,6 @@
}
}
- /**
- * Remove an approved print service.
- *
- * @param serviceToRemove The {@link ComponentName} of the service to be removed.
- */
- public void removeApprovedPrintService(ComponentName serviceToRemove) {
- mSpooler.removeApprovedPrintService(serviceToRemove);
- }
-
public void restartPrintJob(PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
@@ -345,6 +364,8 @@
throwIfDestroyedLocked();
if (mPrinterDiscoverySession == null) {
+ mSpooler.clearCustomPrinterIconCache();
+
// If we do not have a session, tell all service to create one.
mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
@Override
@@ -533,6 +554,20 @@
}
@Override
+ public void onCustomPrinterIconLoaded(PrinterId printerId, Icon icon) {
+ synchronized (mLock) {
+ throwIfDestroyedLocked();
+
+ // No session - nothing to do.
+ if (mPrinterDiscoverySession == null) {
+ return;
+ }
+ mSpooler.onCustomPrinterIconLoaded(printerId, icon);
+ mPrinterDiscoverySession.onCustomPrinterIconLoadedLocked(printerId);
+ }
+ }
+
+ @Override
public void onServiceDied(RemotePrintService service) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -558,13 +593,6 @@
}
}
- public Set<ComponentName> getEnabledServices() {
- synchronized(mLock) {
- throwIfDestroyedLocked();
- return mEnabledServices;
- }
- }
-
public void destroyLocked() {
throwIfDestroyedLocked();
mSpooler.destroy();
@@ -573,7 +601,7 @@
}
mActiveServices.clear();
mInstalledServices.clear();
- mEnabledServices.clear();
+ mDisabledServices.clear();
if (mPrinterDiscoverySession != null) {
mPrinterDiscoverySession.destroyLocked();
mPrinterDiscoverySession = null;
@@ -607,12 +635,12 @@
.append(installedService.getAdvancedOptionsActivityName()).println();
}
- pw.append(prefix).append(tab).append("enabled services:").println();
- for (ComponentName enabledService : mEnabledServices) {
- String enabledServicePrefix = prefix + tab + tab;
- pw.append(enabledServicePrefix).append("service:").println();
- pw.append(enabledServicePrefix).append(tab).append("componentName=")
- .append(enabledService.flattenToString());
+ pw.append(prefix).append(tab).append("disabled services:").println();
+ for (ComponentName disabledService : mDisabledServices) {
+ String disabledServicePrefix = prefix + tab + tab;
+ pw.append(disabledServicePrefix).append("service:").println();
+ pw.append(disabledServicePrefix).append(tab).append("componentName=")
+ .append(disabledService.flattenToString());
pw.println();
}
@@ -640,7 +668,7 @@
private boolean readConfigurationLocked() {
boolean somethingChanged = false;
somethingChanged |= readInstalledPrintServicesLocked();
- somethingChanged |= readEnabledPrintServicesLocked();
+ somethingChanged |= readDisabledPrintServicesLocked();
return somethingChanged;
}
@@ -703,13 +731,50 @@
return false;
}
- private boolean readEnabledPrintServicesLocked() {
- Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>();
- readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
- tempEnabledServiceNameSet);
- if (!tempEnabledServiceNameSet.equals(mEnabledServices)) {
- mEnabledServices.clear();
- mEnabledServices.addAll(tempEnabledServiceNameSet);
+ /**
+ * Update persistent state from a previous version of Android.
+ */
+ private void upgradePersistentStateIfNeeded() {
+ String enabledSettingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
+
+ // Pre N we store the enabled services, in N and later we store the disabled services.
+ // Hence if enabledSettingValue is still set, we need to upgrade.
+ if (enabledSettingValue != null) {
+ Set<ComponentName> enabledServiceNameSet = new HashSet<ComponentName>();
+ readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES,
+ enabledServiceNameSet);
+
+ ArraySet<ComponentName> disabledServices = new ArraySet<>();
+ final int numInstalledServices = mInstalledServices.size();
+ for (int i = 0; i < numInstalledServices; i++) {
+ ComponentName serviceName = mInstalledServices.get(i).getComponentName();
+ if (!enabledServiceNameSet.contains(serviceName)) {
+ disabledServices.add(serviceName);
+ }
+ }
+
+ writeDisabledPrintServicesLocked(disabledServices);
+
+ // We won't needed ENABLED_PRINT_SERVICES anymore, set to null to prevent upgrade to run
+ // again.
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_PRINT_SERVICES, null, mUserId);
+ }
+ }
+
+ /**
+ * Read the set of disabled print services from the secure settings.
+ *
+ * @return true if the state changed.
+ */
+ private boolean readDisabledPrintServicesLocked() {
+ Set<ComponentName> tempDisabledServiceNameSet = new HashSet<ComponentName>();
+ readPrintServicesFromSettingLocked(Settings.Secure.DISABLED_PRINT_SERVICES,
+ tempDisabledServiceNameSet);
+ if (!tempDisabledServiceNameSet.equals(mDisabledServices)) {
+ mDisabledServices.clear();
+ mDisabledServices.addAll(tempDisabledServiceNameSet);
return true;
}
return false;
@@ -735,70 +800,28 @@
}
}
- private void enableSystemPrintServicesLocked() {
- // Load enabled and installed services.
- readEnabledPrintServicesLocked();
- readInstalledPrintServicesLocked();
-
- // Load the system services once enabled on first boot.
- Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>();
- readPrintServicesFromSettingLocked(
- Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
- enabledOnFirstBoot);
-
+ /**
+ * Persist the disabled print services to the secure settings.
+ */
+ private void writeDisabledPrintServicesLocked(Set<ComponentName> disabledServices) {
StringBuilder builder = new StringBuilder();
-
- final int serviceCount = mInstalledServices.size();
- for (int i = 0; i < serviceCount; i++) {
- ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo;
- // Enable system print services if we never did that and are not enabled.
- if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- ComponentName serviceName = new ComponentName(
- serviceInfo.packageName, serviceInfo.name);
- if (!mEnabledServices.contains(serviceName)
- && !enabledOnFirstBoot.contains(serviceName)) {
- if (builder.length() > 0) {
- builder.append(":");
- }
- builder.append(serviceName.flattenToString());
- }
+ for (ComponentName componentName : disabledServices) {
+ if (builder.length() > 0) {
+ builder.append(COMPONENT_NAME_SEPARATOR);
}
- }
-
- // Nothing to be enabled - done.
- if (builder.length() <= 0) {
- return;
- }
-
- String servicesToEnable = builder.toString();
-
- // Update the enabled services setting.
- String enabledServices = Settings.Secure.getStringForUser(
- mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId);
- if (TextUtils.isEmpty(enabledServices)) {
- enabledServices = servicesToEnable;
- } else {
- enabledServices = enabledServices + ":" + servicesToEnable;
+ builder.append(componentName.flattenToShortString());
}
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId);
-
- // Update the enabled on first boot services setting.
- String enabledOnFirstBootServices = Settings.Secure.getStringForUser(
- mContext.getContentResolver(),
- Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId);
- if (TextUtils.isEmpty(enabledOnFirstBootServices)) {
- enabledOnFirstBootServices = servicesToEnable;
- } else {
- enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices;
- }
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES,
- enabledOnFirstBootServices, mUserId);
+ Settings.Secure.DISABLED_PRINT_SERVICES, builder.toString(), mUserId);
}
- private void onConfigurationChangedLocked() {
- Set<ComponentName> installedComponents = new ArraySet<ComponentName>();
+ /**
+ * Get the {@link ComponentName names} of the installed print services
+ *
+ * @return The names of the installed print services
+ */
+ private ArrayList<ComponentName> getInstalledComponents() {
+ ArrayList<ComponentName> installedComponents = new ArrayList<ComponentName>();
final int installedCount = mInstalledServices.size();
for (int i = 0; i < installedCount; i++) {
@@ -807,8 +830,37 @@
resolveInfo.serviceInfo.name);
installedComponents.add(serviceName);
+ }
- if (mEnabledServices.contains(serviceName)) {
+ return installedComponents;
+ }
+
+ /**
+ * Prune persistent state if a print service was uninstalled
+ */
+ public void prunePrintServices() {
+ synchronized (mLock) {
+ ArrayList<ComponentName> installedComponents = getInstalledComponents();
+
+ // Remove unnecessary entries from persistent state "disabled services"
+ boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents);
+ if (disabledServicesUninstalled) {
+ writeDisabledPrintServicesLocked(mDisabledServices);
+ }
+
+ // Remove unnecessary entries from persistent state "approved services"
+ mSpooler.pruneApprovedPrintServices(installedComponents);
+ }
+ }
+
+ private void onConfigurationChangedLocked() {
+ ArrayList<ComponentName> installedComponents = getInstalledComponents();
+
+ final int installedCount = installedComponents.size();
+ for (int i = 0; i < installedCount; i++) {
+ ComponentName serviceName = installedComponents.get(i);
+
+ if (!mDisabledServices.contains(serviceName)) {
if (!mActiveServices.containsKey(serviceName)) {
RemotePrintService service = new RemotePrintService(
mContext, serviceName, mUserId, mSpooler, this);
@@ -973,16 +1025,16 @@
private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
- private final Handler mHandler;
+ private final Handler mSessionHandler;
private boolean mIsDestroyed;
public PrinterDiscoverySessionMediator(Context context) {
- mHandler = new SessionHandler(context.getMainLooper());
+ mSessionHandler = new SessionHandler(context.getMainLooper());
// Kick off the session creation.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
@@ -997,7 +1049,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = observer;
args.arg2 = printers;
- mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
args).sendToTarget();
}
}
@@ -1040,7 +1092,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = services;
args.arg2 = priorityList;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
.sendToTarget();
}
@@ -1060,7 +1112,7 @@
}
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
.sendToTarget();
}
@@ -1094,7 +1146,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = updateList;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_VALIDATE_PRINTERS, args)
.sendToTarget();
}
@@ -1126,7 +1178,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_START_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1153,7 +1205,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_STOP_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1183,7 +1235,7 @@
// Tell the services we are done.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
@@ -1209,7 +1261,7 @@
}
}
if (addedPrinters != null) {
- mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
addedPrinters).sendToTarget();
}
}
@@ -1234,7 +1286,7 @@
}
}
if (removedPrinterIds != null) {
- mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
}
}
@@ -1250,6 +1302,37 @@
service.destroy();
}
+ /**
+ * Handle that a custom icon for a printer was loaded.
+ *
+ * This increments the icon generation and adds the printer again which triggers an update
+ * in all users of the currently known printers.
+ *
+ * @param printerId the id of the printer the icon belongs to
+ * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+ */
+ public void onCustomPrinterIconLoadedLocked(PrinterId printerId) {
+ if (DEBUG) {
+ Log.i(LOG_TAG, "onCustomPrinterIconLoadedLocked()");
+ }
+ if (mIsDestroyed) {
+ Log.w(LOG_TAG, "Not updating printer - session destroyed");
+ return;
+ }
+
+ PrinterInfo printer = mPrinters.get(printerId);
+ if (printer != null) {
+ PrinterInfo newPrinter = (new PrinterInfo.Builder(printer))
+ .incCustomPrinterIconGen().build();
+ mPrinters.put(printerId, newPrinter);
+
+ ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1);
+ addedPrinters.add(newPrinter);
+ mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
+ addedPrinters).sendToTarget();
+ }
+ }
+
public void onServiceDiedLocked(RemotePrintService service) {
// Remove the reported by that service.
removePrintersForServiceLocked(service.getComponentName());
@@ -1261,12 +1344,12 @@
return;
}
// Tell the service to create a session.
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
service).sendToTarget();
// Start printer discovery if necessary.
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_START_PRINTER_DISCOVERY,
service).sendToTarget();
}
@@ -1278,7 +1361,7 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
- mHandler.obtainMessage(SessionHandler
+ mSessionHandler.obtainMessage(SessionHandler
.MSG_START_PRINTER_STATE_TRACKING, args)
.sendToTarget();
}
@@ -1348,7 +1431,7 @@
for (int i = 0; i < removedPrinterCount; i++) {
mPrinters.remove(removedPrinterIds.get(i));
}
- mHandler.obtainMessage(
+ mSessionHandler.obtainMessage(
SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index c12f978..204bc2e 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -18,7 +18,6 @@
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
@@ -49,6 +48,7 @@
import static org.easymock.EasyMock.isA;
import android.app.AlarmManager;
+import android.app.IAlarmListener;
import android.app.IAlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
@@ -70,6 +70,7 @@
import android.test.suitebuilder.annotation.Suppress;
import android.util.TrustedTime;
+import com.android.internal.net.VpnInfo;
import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -83,6 +84,9 @@
/**
* Tests for {@link NetworkStatsService}.
+ *
+ * TODO: This test is really brittle, largely due to overly-strict use of Easymock.
+ * Rewrite w/ Mockito.
*/
@LargeTest
public class NetworkStatsServiceTest extends AndroidTestCase {
@@ -143,7 +147,6 @@
expectCurrentTime();
expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -190,9 +193,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -244,9 +248,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
@@ -295,7 +300,6 @@
// boot through serviceReady() again
expectCurrentTime();
expectDefaultSettings();
- expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -335,9 +339,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// modify some number on wifi, and trigger poll event
@@ -387,9 +392,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some traffic on first network
@@ -429,9 +435,10 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)
.addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L));
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
verifyAndReset();
@@ -475,9 +482,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some traffic
@@ -544,9 +552,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some traffic
@@ -578,9 +587,10 @@
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L)
.addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L));
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
verifyAndReset();
@@ -615,9 +625,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some traffic for two apps
@@ -681,9 +692,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some initial traffic
@@ -746,9 +758,10 @@
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
expectNetworkStatsPoll();
+ expectBandwidthControlCheck();
replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
+ mService.forceUpdateIfaces();
verifyAndReset();
// create some tethering traffic
@@ -778,65 +791,6 @@
}
- public void testReportXtOverDev() throws Exception {
- // bring mobile network online
- expectCurrentTime();
- expectDefaultSettings();
- expectNetworkState(buildMobile3gState(IMSI_1));
- expectNetworkStatsSummary(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
- mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
- verifyAndReset();
-
- // create some traffic, but only for DEV, and across 1.5 buckets
- incrementCurrentTime(90 * MINUTE_IN_MILLIS);
- expectCurrentTime();
- expectDefaultSettings();
- expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1)
- .addIfaceValues(TEST_IFACE, 6000L, 60L, 3000L, 30L));
- expectNetworkStatsSummaryXt(buildEmptyStats());
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-
- // verify service recorded history:
- // 4000(dev) + 2000(dev)
- assertNetworkTotal(sTemplateImsi1, 6000L, 60L, 3000L, 30L, 0);
- verifyAndReset();
-
- // create traffic on both DEV and XT, across two buckets
- incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectCurrentTime();
- expectDefaultSettings();
- expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1)
- .addIfaceValues(TEST_IFACE, 6004L, 64L, 3004L, 34L));
- expectNetworkStatsSummaryXt(new NetworkStats(getElapsedRealtime(), 1)
- .addIfaceValues(TEST_IFACE, 10240L, 0L, 0L, 0L));
- expectNetworkStatsUidDetail(buildEmptyStats());
- expectNetworkStatsPoll();
-
- replay();
- mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-
- // verify that we switching reporting at the first atomic XT bucket,
- // which should give us:
- // 4000(dev) + 2000(dev) + 1(dev) + 5120(xt) + 2560(xt)
- assertNetworkTotal(sTemplateImsi1, 13681L, 61L, 3001L, 31L, 0);
-
- // also test pure-DEV and pure-XT ranges
- assertNetworkTotal(sTemplateImsi1, startTimeMillis(),
- startTimeMillis() + 2 * HOUR_IN_MILLIS, 6001L, 61L, 3001L, 31L, 0);
- assertNetworkTotal(sTemplateImsi1, startTimeMillis() + 2 * HOUR_IN_MILLIS,
- startTimeMillis() + 4 * HOUR_IN_MILLIS, 7680L, 0L, 0L, 0L, 0);
-
- verifyAndReset();
- }
-
private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets,
long txBytes, long txPackets, int operations) throws Exception {
assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes,
@@ -876,19 +830,21 @@
}
private void expectSystemReady() throws Exception {
- mAlarmManager.remove(isA(PendingIntent.class), null);
+ mAlarmManager.remove(isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull());
expectLastCall().anyTimes();
- mAlarmManager.set(getContext().getPackageName(),
+ mAlarmManager.set(eq(getContext().getPackageName()),
eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
- anyInt(), isA(PendingIntent.class), null, null, isA(WorkSource.class),
- isA(AlarmManager.AlarmClockInfo.class));
- expectLastCall().atLeastOnce();
+ anyInt(), isA(PendingIntent.class), EasyMock.<IAlarmListener>isNull(),
+ EasyMock.<String>isNull(), EasyMock.<WorkSource>isNull(),
+ EasyMock.<AlarmManager.AlarmClockInfo>isNull());
+ expectLastCall().anyTimes();
mNetManager.setGlobalAlert(anyLong());
expectLastCall().atLeastOnce();
- expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectBandwidthControlCheck();
}
private void expectNetworkState(NetworkState... state) throws Exception {
@@ -899,6 +855,8 @@
}
private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
+ expect(mConnManager.getAllVpnInfo()).andReturn(new VpnInfo[0]).atLeastOnce();
+
expectNetworkStatsSummaryDev(summary);
expectNetworkStatsSummaryXt(summary);
}
@@ -961,6 +919,10 @@
expectLastCall().anyTimes();
}
+ private void expectBandwidthControlCheck() throws Exception {
+ expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce();
+ }
+
private void assertStatsFilesExist(boolean exist) {
final File basePath = new File(mStatsDir, "netstats");
if (exist) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 435b602..90e4acf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -208,6 +208,11 @@
}
@Override
+ void powerManagerReboot(String reason) {
+ context.powerManager.reboot(reason);
+ }
+
+ @Override
boolean systemPropertiesGetBoolean(String key, boolean def) {
return context.systemProperties.getBoolean(key, def);
}
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 565ef4b..672058b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -758,7 +758,7 @@
when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
// Now call clear.
- doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUid(
+ doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser(
eq(admin1.getPackageName()),
anyInt());
dpm.clearDeviceOwnerApp(admin1.getPackageName());
@@ -797,7 +797,7 @@
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
// Now call clear.
- doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUid(
+ doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser(
eq(admin1.getPackageName()),
anyInt());
try {
@@ -944,6 +944,88 @@
assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
}
+ public void testApplicationRestrictionsManagingApp() throws Exception {
+ setAsProfileOwner(admin1);
+
+ final String appRestrictionsManagerPackage = "com.google.app.restrictions.manager";
+ final int appRestrictionsManagerAppId = 20987;
+ final int appRestrictionsManagerUid = UserHandle.getUid(
+ DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId);
+ doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser(
+ eq(appRestrictionsManagerPackage),
+ eq(DpmMockContext.CALLER_USER_HANDLE));
+ mContext.binder.callingUid = appRestrictionsManagerUid;
+
+ // appRestrictionsManager package shouldn't be able to manage restrictions as the PO hasn't
+ // delegated that permission yet.
+ assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+ Bundle rest = new Bundle();
+ rest.putString("KEY_STRING", "Foo1");
+ try {
+ dpm.setApplicationRestrictions(null, "pkg1", rest);
+ fail("Didn't throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex(
+ "caller cannot manage application restrictions", expected.getMessage());
+ }
+ try {
+ dpm.getApplicationRestrictions(null, "pkg1");
+ fail("Didn't throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex(
+ "caller cannot manage application restrictions", expected.getMessage());
+ }
+
+ // Check via the profile owner that no restrictions were set.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+
+ // Let appRestrictionsManagerPackage manage app restrictions
+ dpm.setApplicationRestrictionsManagingPackage(admin1, appRestrictionsManagerPackage);
+ assertEquals(appRestrictionsManagerPackage,
+ dpm.getApplicationRestrictionsManagingPackage(admin1));
+
+ // Now that package should be able to set and retrieve app restrictions.
+ mContext.binder.callingUid = appRestrictionsManagerUid;
+ assertTrue(dpm.isCallerApplicationRestrictionsManagingPackage());
+ dpm.setApplicationRestrictions(null, "pkg1", rest);
+ Bundle returned = dpm.getApplicationRestrictions(null, "pkg1");
+ assertEquals(1, returned.size(), 1);
+ assertEquals("Foo1", returned.get("KEY_STRING"));
+
+ // The same app running on a separate user shouldn't be able to manage app restrictions.
+ mContext.binder.callingUid = UserHandle.getUid(
+ UserHandle.USER_SYSTEM, appRestrictionsManagerAppId);
+ assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+ try {
+ dpm.setApplicationRestrictions(null, "pkg1", rest);
+ fail("Didn't throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex(
+ "caller cannot manage application restrictions", expected.getMessage());
+ }
+
+ // The DPM is still able to manage app restrictions, even if it allowed another app to do it
+ // too.
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ assertEquals(returned, dpm.getApplicationRestrictions(admin1, "pkg1"));
+ dpm.setApplicationRestrictions(admin1, "pkg1", null);
+ assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg1").size());
+
+ // Removing the ability for the package to manage app restrictions.
+ dpm.setApplicationRestrictionsManagingPackage(admin1, null);
+ assertNull(dpm.getApplicationRestrictionsManagingPackage(admin1));
+ mContext.binder.callingUid = appRestrictionsManagerUid;
+ assertFalse(dpm.isCallerApplicationRestrictionsManagingPackage());
+ try {
+ dpm.setApplicationRestrictions(null, "pkg1", null);
+ fail("Didn't throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex(
+ "caller cannot manage application restrictions", expected.getMessage());
+ }
+ }
+
public void testSetUserRestriction_asDo() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_USERS);
@@ -1267,4 +1349,131 @@
when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
}
+
+ public void testRebootCanOnlyBeCalledByDeviceOwner() throws Exception {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+ // In this test, change the caller user to "system".
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+ // Make sure admin1 is installed on system user.
+ setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+ // Set admin1 as DA.
+ dpm.setActiveAdmin(admin1, false);
+ assertTrue(dpm.isAdminActive(admin1));
+ try {
+ dpm.reboot(admin1);
+ fail("DA calls DPM.reboot(), did not throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+ }
+
+ // Set admin1 as PO.
+ assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
+ try {
+ dpm.reboot(admin1);
+ fail("PO calls DPM.reboot(), did not throw expected SecurityException");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("does not own the device", expected.getMessage());
+ }
+
+ // Remove PO and add DO.
+ dpm.clearProfileOwner(admin1);
+ assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
+
+ dpm.reboot(admin1);
+ }
+
+ public void testSetGetSupportText() {
+ mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+ dpm.setActiveAdmin(admin1, true);
+ dpm.setActiveAdmin(admin2, true);
+ mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
+
+ // Null default support messages.
+ {
+ assertNull(dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin1));
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertNull(dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ }
+
+ // Only system can call the per user versions.
+ {
+ try {
+ dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE);
+ fail("Only system should be able to call getXXXForUser versions");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+ }
+ try {
+ dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE);
+ fail("Only system should be able to call getXXXForUser versions");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+ }
+ }
+
+ // Can't set message for admin in another uid.
+ {
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
+ try {
+ dpm.setShortSupportMessage(admin1, "Some text");
+ fail("Admins should only be able to change their own support text.");
+ } catch (SecurityException expected) {
+ MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage());
+ }
+ mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+ }
+
+ // Set/Get short returns what it sets and other admins text isn't changed.
+ {
+ final String supportText = "Some text to test with.";
+ dpm.setShortSupportMessage(admin1, supportText);
+ assertEquals(supportText, dpm.getShortSupportMessage(admin1));
+ assertNull(dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin2));
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin2,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ dpm.setShortSupportMessage(admin1, null);
+ assertNull(dpm.getShortSupportMessage(admin1));
+ }
+
+ // Set/Get long returns what it sets and other admins text isn't changed.
+ {
+ final String supportText = "Some text to test with.\nWith more text.";
+ dpm.setLongSupportMessage(admin1, supportText);
+ assertEquals(supportText, dpm.getLongSupportMessage(admin1));
+ assertNull(dpm.getShortSupportMessage(admin1));
+ assertNull(dpm.getLongSupportMessage(admin2));
+
+ mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+ assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getLongSupportMessageForUser(admin2,
+ DpmMockContext.CALLER_USER_HANDLE));
+ assertNull(dpm.getShortSupportMessageForUser(admin1,
+ DpmMockContext.CALLER_USER_HANDLE));
+ mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+ dpm.setLongSupportMessage(admin1, null);
+ assertNull(dpm.getLongSupportMessage(admin1));
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 66d701d..56667e5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -134,6 +134,9 @@
public void goToSleep(long time, int reason, int flags) {
}
+
+ public void reboot(String reason) {
+ }
}
public static class SystemPropertiesForMock {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 5b33e4d..c557ab7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -117,7 +117,7 @@
// We need to rewrite the UID in the activity info.
realResolveInfo.get(0).activityInfo.applicationInfo = ai;
- doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
+ doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
MockUtils.checkIntentComponent(admin),
eq(PackageManager.GET_META_DATA
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
new file mode 100644
index 0000000..bb8f9d1
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsAccessTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.net;
+
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.telephony.TelephonyManager;
+
+import com.android.server.LocalServices;
+
+import junit.framework.TestCase;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class NetworkStatsAccessTest extends TestCase {
+ private static final String TEST_PKG = "com.example.test";
+ private static final int TEST_UID = 12345;
+
+ @Mock private Context mContext;
+ @Mock private DevicePolicyManagerInternal mDpmi;
+ @Mock private TelephonyManager mTm;
+ @Mock private AppOpsManager mAppOps;
+
+ // Hold the real service so we can restore it when tearing down the test.
+ private DevicePolicyManagerInternal mSystemDpmi;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+
+ mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
+
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
+ when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
+ super.tearDown();
+ }
+
+ public void testCheckAccessLevel_hasCarrierPrivileges() throws Exception {
+ setHasCarrierPrivileges(true);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(false);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.DEVICE,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_isDeviceOwner() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(true);
+ setIsProfileOwner(false);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.DEVICE,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_isProfileOwner() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(true);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.USER,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_hasAppOpsBitAllowed() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(true);
+ setHasAppOpsPermission(AppOpsManager.MODE_ALLOWED, false);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.USER,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_hasAppOpsBitDefault_grantedPermission() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(true);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, true);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.USER,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_hasReadHistoryPermission() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(true);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
+ setHasReadHistoryPermission(true);
+ assertEquals(NetworkStatsAccess.Level.USER,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_deniedAppOpsBit() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(false);
+ setHasAppOpsPermission(AppOpsManager.MODE_ERRORED, true);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.DEFAULT,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ public void testCheckAccessLevel_deniedAppOpsBit_deniedPermission() throws Exception {
+ setHasCarrierPrivileges(false);
+ setIsDeviceOwner(false);
+ setIsProfileOwner(false);
+ setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
+ setHasReadHistoryPermission(false);
+ assertEquals(NetworkStatsAccess.Level.DEFAULT,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_UID, TEST_PKG));
+ }
+
+ private void setHasCarrierPrivileges(boolean hasPrivileges) {
+ when(mTm.checkCarrierPrivilegesForPackage(TEST_PKG)).thenReturn(
+ hasPrivileges ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS);
+ }
+
+ private void setIsDeviceOwner(boolean isOwner) {
+ when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
+ .thenReturn(isOwner);
+ }
+
+ private void setIsProfileOwner(boolean isOwner) {
+ when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
+ .thenReturn(isOwner);
+ }
+
+ private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
+ when(mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
+ .thenReturn(appOpsMode);
+ when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
+ hasPermission ? PackageManager.PERMISSION_GRANTED
+ : PackageManager.PERMISSION_DENIED);
+ }
+
+ private void setHasReadHistoryPermission(boolean hasPermission) {
+ when(mContext.checkCallingOrSelfPermission(permission.READ_NETWORK_USAGE_HISTORY))
+ .thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
+ : PackageManager.PERMISSION_DENIED);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
index 1a6c289..6026644 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java
@@ -16,6 +16,7 @@
package com.android.server.net;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
@@ -24,9 +25,14 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.content.res.Resources;
+import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
+import android.os.Process;
+import android.os.UserHandle;
+import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.frameworks.servicestests.R;
@@ -68,7 +74,7 @@
// verify that history read correctly
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L);
+ 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -77,12 +83,12 @@
// clear structure completely
collection.reset();
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L);
+ 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
// and read back into structure, verifying that totals are same
collection.read(new ByteArrayInputStream(bos.toByteArray()));
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 636016770L, 709306L, 88038768L, 518836L);
+ 636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
}
public void testReadLegacyUid() throws Exception {
@@ -94,7 +100,7 @@
// verify that history read correctly
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L);
+ 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
// now export into a unified format
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -103,12 +109,12 @@
// clear structure completely
collection.reset();
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 0L, 0L, 0L, 0L);
+ 0L, 0L, 0L, 0L, NetworkStatsAccess.Level.DEVICE);
// and read back into structure, verifying that totals are same
collection.read(new ByteArrayInputStream(bos.toByteArray()));
assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI),
- 637076152L, 711413L, 88343717L, 521022L);
+ 637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
}
public void testReadLegacyUidTags() throws Exception {
@@ -151,6 +157,66 @@
assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
}
+ public void testAccessLevels() throws Exception {
+ final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ final NetworkIdentitySet identSet = new NetworkIdentitySet();
+ identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ TEST_IMSI, null, false));
+
+ int myUid = Process.myUid();
+ int otherUidInSameUser = Process.myUid() + 1;
+ int uidInDifferentUser = Process.myUid() + UserHandle.PER_USER_RANGE;
+
+ // Record one entry for the current UID.
+ entry.rxBytes = 32;
+ collection.recordData(identSet, myUid, SET_DEFAULT, TAG_NONE, 0, 60 * MINUTE_IN_MILLIS,
+ entry);
+
+ // Record one entry for another UID in this user.
+ entry.rxBytes = 64;
+ collection.recordData(identSet, otherUidInSameUser, SET_DEFAULT, TAG_NONE, 0,
+ 60 * MINUTE_IN_MILLIS, entry);
+
+ // Record one entry for the system UID.
+ entry.rxBytes = 128;
+ collection.recordData(identSet, Process.SYSTEM_UID, SET_DEFAULT, TAG_NONE, 0,
+ 60 * MINUTE_IN_MILLIS, entry);
+
+ // Record one entry for a UID in a different user.
+ entry.rxBytes = 256;
+ collection.recordData(identSet, uidInDifferentUser, SET_DEFAULT, TAG_NONE, 0,
+ 60 * MINUTE_IN_MILLIS, entry);
+
+ // Verify the set of relevant UIDs for each access level.
+ MoreAsserts.assertEquals(new int[] { myUid },
+ collection.getRelevantUids(NetworkStatsAccess.Level.DEFAULT));
+ MoreAsserts.assertEquals(new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser },
+ collection.getRelevantUids(NetworkStatsAccess.Level.USER));
+ MoreAsserts.assertEquals(
+ new int[] { Process.SYSTEM_UID, myUid, otherUidInSameUser, uidInDifferentUser },
+ collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
+
+ // Verify security check in getHistory.
+ assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), myUid, SET_DEFAULT,
+ TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT));
+ try {
+ collection.getHistory(buildTemplateMobileAll(TEST_IMSI), otherUidInSameUser,
+ SET_DEFAULT, TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT);
+ fail("Should have thrown SecurityException for accessing different UID");
+ } catch (SecurityException e) {
+ // expected
+ }
+
+ // Verify appropriate aggregation in getSummary.
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32, 0, 0, 0,
+ NetworkStatsAccess.Level.DEFAULT);
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128, 0, 0, 0,
+ NetworkStatsAccess.Level.USER);
+ assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), 32 + 64 + 128 + 256, 0, 0,
+ 0, NetworkStatsAccess.Level.DEVICE);
+ }
+
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.
@@ -170,16 +236,19 @@
}
private static void assertSummaryTotal(NetworkStatsCollection collection,
- NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
+ NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
+ @NetworkStatsAccess.Level int accessLevel) {
final NetworkStats.Entry entry = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null);
+ template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel)
+ .getTotal(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
}
private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
final NetworkStats.Entry entry = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE).getTotalIncludingTags(null);
+ template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE)
+ .getTotalIncludingTags(null);
assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index df7b412..2640889 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -35,7 +35,7 @@
public class RankingHelperTest extends AndroidTestCase {
@Mock NotificationUsageStats mUsageStats;
- @Mock Handler handler;
+ @Mock RankingHandler handler;
private Notification mNotiGroupGSortA;
private Notification mNotiGroupGSortB;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2b0919b..23e8894 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -374,7 +374,7 @@
for (int i = 0; i < userIds.length; i++) {
final int userId = userIds[i];
List<PackageInfo> packages =
- getContext().getPackageManager().getInstalledPackages(
+ getContext().getPackageManager().getInstalledPackagesAsUser(
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_UNINSTALLED_PACKAGES,
userId);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 5188e5f..72621a42 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -148,7 +148,7 @@
private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime,
boolean firstUpdate) {
PackageManager pm = mContext.getPackageManager();
- List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId);
+ List<PackageInfo> packages = pm.getInstalledPackagesAsUser(0, mUserId);
final int packageCount = packages.size();
for (int i = 0; i < packageCount; i++) {
final PackageInfo pi = packages.get(i);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8a1a553..aa95e1d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -242,8 +242,13 @@
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
+ /**
+ * Whether the call is associated with the work profile.
+ */
+ public static final int PROPERTY_WORK_CALL = 0x00000020;
+
//******************************************************************************************
- // Next PROPERTY value: 0x00000020
+ // Next PROPERTY value: 0x00000040
//******************************************************************************************
private final Uri mHandle;
@@ -269,7 +274,7 @@
* @return Whether the specified capability is supported.
*/
public static boolean can(int capabilities, int capability) {
- return (capabilities & capability) != 0;
+ return (capabilities & capability) == capability;
}
/**
@@ -351,7 +356,7 @@
* @return Whether the specified property is supported.
*/
public static boolean hasProperty(int properties, int property) {
- return (properties & property) != 0;
+ return (properties & property) == property;
}
/**
@@ -684,7 +689,7 @@
private int mState;
private List<String> mCannedTextResponses = null;
private String mRemainingPostDialSequence;
- private InCallService.VideoCall mVideoCall;
+ private VideoCallImpl mVideoCallImpl;
private Details mDetails;
/**
@@ -897,7 +902,7 @@
* @return An {@code Call.VideoCall}.
*/
public InCallService.VideoCall getVideoCall() {
- return mVideoCall;
+ return mVideoCallImpl;
}
/**
@@ -1028,10 +1033,14 @@
cannedTextResponsesChanged = true;
}
+ VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
- !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this));
+ !Objects.equals(mVideoCallImpl, newVideoCallImpl);
if (videoCallChanged) {
- mVideoCall = parcelableCall.getVideoCall(this);
+ mVideoCallImpl = newVideoCallImpl;
+ }
+ if (mVideoCallImpl != null) {
+ mVideoCallImpl.setVideoState(getDetails().getVideoState());
}
int state = parcelableCall.getState();
@@ -1081,7 +1090,7 @@
fireCannedTextResponsesLoaded(mCannedTextResponses);
}
if (videoCallChanged) {
- fireVideoCallChanged(mVideoCall);
+ fireVideoCallChanged(mVideoCallImpl);
}
if (parentChanged) {
fireParentChanged(getParent());
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 17bd08c..deb98f4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -294,7 +294,7 @@
* @hide
*/
public static boolean can(int capabilities, int capability) {
- return (capabilities & capability) != 0;
+ return (capabilities & capability) == capability;
}
/**
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 5852b8e..a915d37 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -207,8 +207,8 @@
}
final List<String> result = new ArrayList<>();
- final List<ResolveInfo> resolveInfoList =
- context.getPackageManager().queryIntentActivities(intent, 0);
+ final List<ResolveInfo> resolveInfoList = context.getPackageManager()
+ .queryIntentActivities(intent, 0);
final int length = resolveInfoList.size();
for (int i = 0; i < length; i++) {
final ActivityInfo info = resolveInfoList.get(i).activityInfo;
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5087080..426b240 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -49,7 +49,7 @@
* <pre>
* {@code
* <service android:name="your.package.YourInCallServiceImplementation"
- * android:permission="android.permission.BIND_IN_CALL_SERVICE">
+ * android:permission="android.permission.BIND_INCALL_SERVICE">
* <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
* <intent-filter>
* <action android:name="android.telecom.InCallService"/>
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 8cf4aeb..4a6fd7c 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -48,7 +48,7 @@
private final PhoneAccountHandle mAccountHandle;
private final boolean mIsVideoCallProviderChanged;
private final IVideoProvider mVideoCallProvider;
- private InCallService.VideoCall mVideoCall;
+ private VideoCallImpl mVideoCall;
private final String mParentCallId;
private final List<String> mChildCallIds;
private final StatusHints mStatusHints;
@@ -179,12 +179,13 @@
/**
* Returns an object for remotely communicating through the video call provider's binder.
+
* @return The video call.
*/
- public InCallService.VideoCall getVideoCall(Call call) {
+ public VideoCallImpl getVideoCallImpl() {
if (mVideoCall == null && mVideoCallProvider != null) {
try {
- mVideoCall = new VideoCallImpl(mVideoCallProvider, call);
+ mVideoCall = new VideoCallImpl(mVideoCallProvider);
} catch (RemoteException ignored) {
// Ignore RemoteException.
}
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 93484cd..e54abee 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -42,7 +42,7 @@
private final VideoCallListenerBinder mBinder;
private VideoCall.Callback mCallback;
private int mVideoQuality = VideoProfile.QUALITY_UNKNOWN;
- private Call mCall;
+ private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
@@ -197,13 +197,12 @@
private Handler mHandler;
- VideoCallImpl(IVideoProvider videoProvider, Call call) throws RemoteException {
+ VideoCallImpl(IVideoProvider videoProvider) throws RemoteException {
mVideoProvider = videoProvider;
mVideoProvider.asBinder().linkToDeath(mDeathRecipient, 0);
mBinder = new VideoCallListenerBinder();
mVideoProvider.addVideoCallback(mBinder);
- mCall = call;
}
public void destroy() {
@@ -292,8 +291,7 @@
*/
public void sendSessionModifyRequest(VideoProfile requestProfile) {
try {
- VideoProfile originalProfile = new VideoProfile(mCall.getDetails().getVideoState(),
- mVideoQuality);
+ VideoProfile originalProfile = new VideoProfile(mVideoState, mVideoQuality);
mVideoProvider.sendSessionModifyRequest(originalProfile, requestProfile);
} catch (RemoteException e) {
@@ -331,4 +329,12 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * Sets the video state for the current video call.
+ * @param videoState the new video state.
+ */
+ public void setVideoState(int videoState) {
+ mVideoState = videoState;
+ }
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8537f9c..c680999 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -153,6 +153,17 @@
* @hide
*/
public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+
+ /** @hide */
+ public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
+ (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_IS95B - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_1xRTT - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_0 - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_A - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1))
+ | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1));
+
/**
* Available registration states for GSM, UMTS and CDMA.
*/
@@ -1141,16 +1152,8 @@
}
/** @hide */
- public static boolean hasCdma(int radioTechnologyBitmask) {
- int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
- | RIL_RADIO_TECHNOLOGY_IS95B
- | RIL_RADIO_TECHNOLOGY_1xRTT
- | RIL_RADIO_TECHNOLOGY_EVDO_0
- | RIL_RADIO_TECHNOLOGY_EVDO_A
- | RIL_RADIO_TECHNOLOGY_EVDO_B
- | RIL_RADIO_TECHNOLOGY_EHRPD);
-
- return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+ public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
+ return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
}
/** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 36407e1..9998937 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1207,7 +1207,7 @@
}
} catch (RemoteException ex) {
}
- logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx);
+
return simState;
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3b281e2..0b5aaa3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -766,7 +766,7 @@
IPhoneSubInfo info = getSubscriberInfo();
if (info == null)
return null;
- return info.getDeviceIdForPhone(slotId);
+ return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4865,4 +4865,4 @@
}
return null;
}
-}
\ No newline at end of file
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index ed85392..dc2b297 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -36,7 +36,7 @@
* Retrieves the unique device ID of a phone for the device, e.g., IMEI
* for GSM phones.
*/
- String getDeviceIdForPhone(int phoneId);
+ String getDeviceIdForPhone(int phoneId, String callingPackage);
/**
* Retrieves the IMEI.
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index f7c63d1..5381e4ef6 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -34,7 +34,6 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -97,14 +96,30 @@
}
@Override
-
public int[] getPackageGids(String packageName) throws NameNotFoundException {
throw new UnsupportedOperationException();
}
+ @Override
+ public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
/** @hide */
@Override
- public int getPackageUid(String packageName, int userHandle)
+ public int getPackageUidAsUser(String packageName, int flags, int userHandle)
+ throws NameNotFoundException {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public int getPackageUidAsUser(String packageName, int userHandle)
throws NameNotFoundException {
throw new UnsupportedOperationException();
}
@@ -175,7 +190,7 @@
/** @hide */
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
throw new UnsupportedOperationException();
}
@@ -356,7 +371,7 @@
/** @hide */
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
throw new UnsupportedOperationException();
}
@@ -747,7 +762,7 @@
* @hide - to match hiding in superclass
*/
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
throw new UnsupportedOperationException();
}
@@ -808,13 +823,19 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean setPackageSuspendedAsUser(String packageName, boolean hidden, int userId) {
+ return false;
+ }
+
/**
* @hide
*/
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
throw new UnsupportedOperationException();
}
@@ -885,7 +906,7 @@
* @hide
*/
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
throw new UnsupportedOperationException();
}
@@ -893,7 +914,7 @@
* @hide
*/
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
throw new UnsupportedOperationException();
}
@@ -910,16 +931,30 @@
throw new UnsupportedOperationException();
}
- @Override
+ /** {@removed} */
+ @Deprecated
public String getDefaultBrowserPackageName(int userId) {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
@Override
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** {@removed} */
+ @Deprecated
public boolean setDefaultBrowserPackageName(String packageName, int userId) {
throw new UnsupportedOperationException();
}
+ /** {@hide} */
+ @Override
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* @hide
*/
@@ -951,7 +986,7 @@
@Override
public void installPackageWithVerification(Uri packageURI,
PackageInstallObserver observer, int flags, String installerPackageName,
- Uri verificationURI, ManifestDigest manifestDigest,
+ Uri verificationURI,
ContainerEncryptionParams encryptionParams) {
throw new UnsupportedOperationException();
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index cf1a4aa..fecfdf9 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -23,6 +23,7 @@
import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Vibrator;
@@ -180,6 +181,9 @@
new Test("with topic GoodBye") {
public void run() {
+ Notification.BigPictureStyle picture = new Notification.BigPictureStyle();
+ picture.bigPicture(BitmapFactory.decodeResource(getResources(),
+ R.id.large_icon_pineapple2));
Notification n = new Notification.Builder(NotificationTestList.this)
.setSmallIcon(R.drawable.icon1)
.setWhen(mActivityCreateTime)
@@ -187,11 +191,29 @@
.setContentText("This is a notification!!!")
.setContentIntent(makeIntent2())
.setTopic(new Notification.Topic("bye", "Goodbye"))
+ .setStyle(picture)
.build();
mNM.notify(9999, n);
}
},
+ new Test("with topic Bananas") {
+ public void run() {
+ Notification.BigTextStyle bigText = new Notification.BigTextStyle();
+ bigText.bigText("bananas are great\nso tasty\nyum\nyum\nyum\n");
+ Notification n = new Notification.Builder(NotificationTestList.this)
+ .setSmallIcon(R.drawable.icon1)
+ .setStyle(bigText)
+ .setWhen(mActivityCreateTime)
+ .setContentTitle("bananananana")
+ .setContentText("This is a banana!!!")
+ .setContentIntent(makeIntent2())
+ .setTopic(new Notification.Topic("bananas", "Bananas"))
+ .build();
+
+ mNM.notify(999, n);
+ }
+ },
new Test("Whens") {
public void run()
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 3c2659f..b78fd49 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
try {
mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
- Configuration.EMPTY, false);
+ Configuration.EMPTY, false, false);
fail("IWindowManager.addAppToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index e4738f5..5ad3379 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -1095,13 +1095,6 @@
analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette,
&paletteEntries, &hasTransparency, &color_type, outRows);
- // If the image is a 9-patch, we need to preserve it as a ARGB file to make
- // sure the pixels will not be pre-dithered/clamped until we decide they are
- if (imageInfo.is9Patch && (color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)) {
- color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- }
-
if (kIsDebug) {
switch (color_type) {
case PNG_COLOR_TYPE_PALETTE:
@@ -1180,18 +1173,11 @@
}
for (int i = 0; i < chunk_count; i++) {
- unknowns[i].location = PNG_HAVE_PLTE;
+ unknowns[i].location = PNG_HAVE_IHDR;
}
png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS,
chunk_names, chunk_count);
png_set_unknown_chunks(write_ptr, write_info, unknowns, chunk_count);
-#if PNG_LIBPNG_VER < 10600
- /* Deal with unknown chunk location bug in 1.5.x and earlier */
- png_set_unknown_chunk_location(write_ptr, write_info, 0, PNG_HAVE_PLTE);
- if (imageInfo.haveLayoutBounds) {
- png_set_unknown_chunk_location(write_ptr, write_info, 1, PNG_HAVE_PLTE);
- }
-#endif
}
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 0f83980..a4f4ba9 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -27,6 +27,8 @@
sources := \
compile/IdAssigner.cpp \
compile/Png.cpp \
+ compile/PseudolocaleGenerator.cpp \
+ compile/Pseudolocalizer.cpp \
compile/XmlIdCollector.cpp \
flatten/Archive.cpp \
flatten/TableFlattener.cpp \
@@ -66,6 +68,8 @@
testSources := \
compile/IdAssigner_test.cpp \
+ compile/PseudolocaleGenerator_test.cpp \
+ compile/Pseudolocalizer_test.cpp \
compile/XmlIdCollector_test.cpp \
flatten/FileExportWriter_test.cpp \
flatten/TableFlattener_test.cpp \
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index d864f66..5fce2c1 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -52,13 +52,17 @@
void visit(Style* style) override {
std::cout << "(style)";
if (style->parent) {
+ const Reference& parentRef = style->parent.value();
std::cout << " parent=";
- if (style->parent.value().name) {
- std::cout << style->parent.value().name.value() << " ";
+ if (parentRef.name) {
+ if (parentRef.privateReference) {
+ std::cout << "*";
+ }
+ std::cout << parentRef.name.value() << " ";
}
- if (style->parent.value().id) {
- std::cout << style->parent.value().id.value();
+ if (parentRef.id) {
+ std::cout << parentRef.id.value();
}
}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index d4c536f..e1f9642d 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -19,9 +19,12 @@
#include "ResourceUtils.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "util/Comparators.h"
+#include "util/ImmutableMap.h"
#include "util/Util.h"
#include "xml/XmlPullParser.h"
+#include <functional>
#include <sstream>
namespace aapt {
@@ -35,6 +38,111 @@
return ns.empty() && (name == u"skip" || name == u"eat-comment");
}
+static uint32_t parseFormatType(const StringPiece16& piece) {
+ if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE;
+ else if (piece == u"string") return android::ResTable_map::TYPE_STRING;
+ else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER;
+ else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN;
+ else if (piece == u"color") return android::ResTable_map::TYPE_COLOR;
+ else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT;
+ else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
+ else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION;
+ else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM;
+ else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS;
+ return 0;
+}
+
+static uint32_t parseFormatAttribute(const StringPiece16& str) {
+ uint32_t mask = 0;
+ for (StringPiece16 part : util::tokenize(str, u'|')) {
+ StringPiece16 trimmedPart = util::trimWhitespace(part);
+ uint32_t type = parseFormatType(trimmedPart);
+ if (type == 0) {
+ return 0;
+ }
+ mask |= type;
+ }
+ return mask;
+}
+
+/**
+ * A parsed resource ready to be added to the ResourceTable.
+ */
+struct ParsedResource {
+ ResourceName name;
+ Source source;
+ ResourceId id;
+ Maybe<SymbolState> symbolState;
+ std::u16string comment;
+ std::unique_ptr<Value> value;
+ std::list<ParsedResource> childResources;
+};
+
+bool ResourceParser::shouldStripResource(const ResourceNameRef& name,
+ const Maybe<std::u16string>& product) const {
+ if (product) {
+ for (const std::u16string& productToMatch : mOptions.products) {
+ if (product.value() == productToMatch) {
+ // We specified a product, and it is in the list, so don't strip.
+ return false;
+ }
+ }
+ }
+
+ // Nothing matched, try 'default'. Default only matches if we didn't already use another
+ // product variant.
+ if (!product || product.value() == u"default") {
+ if (Maybe<ResourceTable::SearchResult> result = mTable->findResource(name)) {
+ const ResourceEntry* entry = result.value().entry;
+ auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), mConfig,
+ cmp::lessThanConfig);
+ if (iter != entry->values.end() && iter->config == mConfig && !iter->value->isWeak()) {
+ // We have a value for this config already, and it is not weak,
+ // so filter out this default.
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+// Recursively adds resources to the ResourceTable.
+static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
+ IDiagnostics* diag, ParsedResource* res) {
+ if (res->symbolState) {
+ Symbol symbol;
+ symbol.state = res->symbolState.value();
+ symbol.source = res->source;
+ symbol.comment = res->comment;
+ if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
+ return false;
+ }
+ }
+
+ if (res->value) {
+ // Attach the comment, source and config to the value.
+ res->value->setComment(std::move(res->comment));
+ res->value->setSource(std::move(res->source));
+
+ if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
+ return false;
+ }
+ }
+
+ bool error = false;
+ for (ParsedResource& child : res->childResources) {
+ error |= !addResourcesToTable(table, config, diag, &child);
+ }
+ return !error;
+}
+
+// Convenient aliases for more readable function calls.
+enum {
+ kAllowRawString = true,
+ kNoRawString = false
+};
+
ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
const ConfigDescription& config,
const ResourceParserOptions& options) :
@@ -146,69 +254,6 @@
return !error;
}
-static bool shouldStripResource(const xml::XmlPullParser* parser,
- const Maybe<std::u16string> productToMatch) {
- assert(parser->getEvent() == xml::XmlPullParser::Event::kStartElement);
-
- if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
- if (!productToMatch) {
- if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") {
- // We didn't specify a product and this is not a default product, so skip.
- return true;
- }
- } else {
- if (productToMatch && maybeProduct.value() != productToMatch.value()) {
- // We specified a product, but they don't match.
- return true;
- }
- }
- }
- return false;
-}
-
-/**
- * A parsed resource ready to be added to the ResourceTable.
- */
-struct ParsedResource {
- ResourceName name;
- Source source;
- ResourceId id;
- Maybe<SymbolState> symbolState;
- std::u16string comment;
- std::unique_ptr<Value> value;
- std::list<ParsedResource> childResources;
-};
-
-// Recursively adds resources to the ResourceTable.
-static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
- IDiagnostics* diag, ParsedResource* res) {
- if (res->symbolState) {
- Symbol symbol;
- symbol.state = res->symbolState.value();
- symbol.source = res->source;
- symbol.comment = res->comment;
- if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
- return false;
- }
- }
-
- if (res->value) {
- // Attach the comment, source and config to the value.
- res->value->setComment(std::move(res->comment));
- res->value->setSource(std::move(res->source));
-
- if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
- return false;
- }
- }
-
- bool error = false;
- for (ParsedResource& child : res->childResources) {
- error |= !addResourcesToTable(table, config, diag, &child);
- }
- return !error;
-}
-
bool ResourceParser::parseResources(xml::XmlPullParser* parser) {
std::set<ResourceName> strippedResources;
@@ -244,118 +289,28 @@
continue;
}
- if (elementName == u"item") {
- // Items simply have their type encoded in the type attribute.
- if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
- elementName = maybeType.value().toString();
- } else {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "<item> must have a 'type' attribute");
- error = true;
- continue;
- }
- }
-
ParsedResource parsedResource;
parsedResource.source = mSource.withLine(parser->getLineNumber());
parsedResource.comment = std::move(comment);
- if (Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name")) {
- parsedResource.name.entry = maybeName.value().toString();
+ // Extract the product name if it exists.
+ Maybe<std::u16string> product;
+ if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) {
+ product = maybeProduct.value().toString();
+ }
- } else if (elementName != u"public-group") {
- mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "<" << elementName << "> tag must have a 'name' attribute");
+ // Parse the resource regardless of product.
+ if (!parseResource(parser, &parsedResource)) {
error = true;
continue;
}
- // Check if we should skip this product.
- const bool stripResource = shouldStripResource(parser, mOptions.product);
-
- bool result = true;
- if (elementName == u"id") {
- parsedResource.name.type = ResourceType::kId;
- parsedResource.value = util::make_unique<Id>();
- } else if (elementName == u"string") {
- parsedResource.name.type = ResourceType::kString;
- result = parseString(parser, &parsedResource);
- } else if (elementName == u"color") {
- parsedResource.name.type = ResourceType::kColor;
- result = parseColor(parser, &parsedResource);
- } else if (elementName == u"drawable") {
- parsedResource.name.type = ResourceType::kDrawable;
- result = parseColor(parser, &parsedResource);
- } else if (elementName == u"bool") {
- parsedResource.name.type = ResourceType::kBool;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"integer") {
- parsedResource.name.type = ResourceType::kInteger;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"dimen") {
- parsedResource.name.type = ResourceType::kDimen;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"fraction") {
- parsedResource.name.type = ResourceType::kFraction;
- result = parsePrimitive(parser, &parsedResource);
- } else if (elementName == u"style") {
- parsedResource.name.type = ResourceType::kStyle;
- result = parseStyle(parser, &parsedResource);
- } else if (elementName == u"plurals") {
- parsedResource.name.type = ResourceType::kPlurals;
- result = parsePlural(parser, &parsedResource);
- } else if (elementName == u"array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY);
- } else if (elementName == u"string-array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING);
- } else if (elementName == u"integer-array") {
- parsedResource.name.type = ResourceType::kArray;
- result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER);
- } else if (elementName == u"declare-styleable") {
- parsedResource.name.type = ResourceType::kStyleable;
- result = parseDeclareStyleable(parser, &parsedResource);
- } else if (elementName == u"attr") {
- parsedResource.name.type = ResourceType::kAttr;
- result = parseAttr(parser, &parsedResource);
- } else if (elementName == u"public") {
- result = parsePublic(parser, &parsedResource);
- } else if (elementName == u"java-symbol" || elementName == u"symbol") {
- result = parseSymbol(parser, &parsedResource);
- } else if (elementName == u"public-group") {
- result = parsePublicGroup(parser, &parsedResource);
- } else if (elementName == u"add-resource") {
- result = parseAddResource(parser, &parsedResource);
- } else {
- // Try parsing the elementName (or type) as a resource. These shall only be
- // resources like 'layout' or 'xml' and they can only be references.
- if (const ResourceType* type = parseResourceType(elementName)) {
- parsedResource.name.type = *type;
- parsedResource.value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE,
- false);
- if (!parsedResource.value) {
- mDiag->error(DiagMessage(parsedResource.source) << "invalid value for type '"
- << *type << "'. Expected a reference");
- result = false;
- }
- } else {
- mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber()))
- << "unknown resource type '" << elementName << "'");
- }
- }
-
- if (result) {
- // We successfully parsed the resource.
-
- if (stripResource) {
- // Record that we stripped out this resource name.
- // We will check that at least one variant of this resource was included.
- strippedResources.insert(parsedResource.name);
- } else {
- error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource);
- }
- } else {
+ // We successfully parsed the resource. Check if we should include it or strip it.
+ if (shouldStripResource(parsedResource.name, product)) {
+ // Record that we stripped out this resource name.
+ // We will check that at least one variant of this resource was included.
+ strippedResources.insert(parsedResource.name);
+ } else if (!addResourcesToTable(mTable, mConfig, mDiag, &parsedResource)) {
error = true;
}
}
@@ -373,10 +328,173 @@
return !error;
}
-enum {
- kAllowRawString = true,
- kNoRawString = false
-};
+
+bool ResourceParser::parseResource(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ struct ItemTypeFormat {
+ ResourceType type;
+ uint32_t format;
+ };
+
+ using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>;
+
+ static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({
+ { u"bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } },
+ { u"color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } },
+ { u"dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT
+ | android::ResTable_map::TYPE_FRACTION
+ | android::ResTable_map::TYPE_DIMENSION } },
+ { u"drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } },
+ { u"fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT
+ | android::ResTable_map::TYPE_FRACTION
+ | android::ResTable_map::TYPE_DIMENSION } },
+ { u"integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } },
+ { u"string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } },
+ });
+
+ static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({
+ { u"add-resource", std::mem_fn(&ResourceParser::parseAddResource) },
+ { u"array", std::mem_fn(&ResourceParser::parseArray) },
+ { u"attr", std::mem_fn(&ResourceParser::parseAttr) },
+ { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) },
+ { u"integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) },
+ { u"java-symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ { u"plurals", std::mem_fn(&ResourceParser::parsePlural) },
+ { u"public", std::mem_fn(&ResourceParser::parsePublic) },
+ { u"public-group", std::mem_fn(&ResourceParser::parsePublicGroup) },
+ { u"string-array", std::mem_fn(&ResourceParser::parseStringArray) },
+ { u"style", std::mem_fn(&ResourceParser::parseStyle) },
+ { u"symbol", std::mem_fn(&ResourceParser::parseSymbol) },
+ });
+
+ std::u16string resourceType = parser->getElementName();
+
+ // The value format accepted for this resource.
+ uint32_t resourceFormat = 0u;
+
+ if (resourceType == u"item") {
+ // Items have their type encoded in the type attribute.
+ if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) {
+ resourceType = maybeType.value().toString();
+ } else {
+ mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber()))
+ << "<item> must have a 'type' attribute");
+ return false;
+ }
+
+ if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) {
+ // An explicit format for this resource was specified. The resource will retain
+ // its type in its name, but the accepted value for this type is overridden.
+ resourceFormat = parseFormatType(maybeFormat.value());
+ if (!resourceFormat) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "'" << maybeFormat.value() << "' is an invalid format");
+ return false;
+ }
+ }
+ }
+
+ // Get the name of the resource. This will be checked later, because not all
+ // XML elements require a name.
+ Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name");
+
+ if (resourceType == u"id") {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = ResourceType::kId;
+ outResource->name.entry = maybeName.value().toString();
+ outResource->value = util::make_unique<Id>();
+ return true;
+ }
+
+ const auto itemIter = elToItemMap.find(resourceType);
+ if (itemIter != elToItemMap.end()) {
+ // This is an item, record its type and format and start parsing.
+
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = itemIter->second.type;
+ outResource->name.entry = maybeName.value().toString();
+
+ // Only use the implicit format for this type if it wasn't overridden.
+ if (!resourceFormat) {
+ resourceFormat = itemIter->second.format;
+ }
+
+ if (!parseItem(parser, outResource, resourceFormat)) {
+ return false;
+ }
+ return true;
+ }
+
+ // This might be a bag or something.
+ const auto bagIter = elToBagMap.find(resourceType);
+ if (bagIter != elToBagMap.end()) {
+ // Ensure we have a name (unless this is a <public-group>).
+ if (resourceType != u"public-group") {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.entry = maybeName.value().toString();
+ }
+
+ // Call the associated parse method. The type will be filled in by the
+ // parse func.
+ if (!bagIter->second(this, parser, outResource)) {
+ return false;
+ }
+ return true;
+ }
+
+ // Try parsing the elementName (or type) as a resource. These shall only be
+ // resources like 'layout' or 'xml' and they can only be references.
+ const ResourceType* parsedType = parseResourceType(resourceType);
+ if (parsedType) {
+ if (!maybeName) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> missing 'name' attribute");
+ return false;
+ }
+
+ outResource->name.type = *parsedType;
+ outResource->name.entry = maybeName.value().toString();
+ outResource->value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
+ if (!outResource->value) {
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid value for type '" << *parsedType << "'. Expected a reference");
+ return false;
+ }
+ return true;
+ }
+
+ mDiag->warn(DiagMessage(outResource->source)
+ << "unknown resource type '" << parser->getElementName() << "'");
+ return false;
+}
+
+bool ResourceParser::parseItem(xml::XmlPullParser* parser, ParsedResource* outResource,
+ const uint32_t format) {
+ if (format == android::ResTable_map::TYPE_STRING) {
+ return parseString(parser, outResource);
+ }
+
+ outResource->value = parseXml(parser, format, kNoRawString);
+ if (!outResource->value) {
+ mDiag->error(DiagMessage(outResource->source) << "invalid " << outResource->name.type);
+ return false;
+ }
+ return true;
+}
/**
* Reads the entire XML subtree and attempts to parse it as some Item,
@@ -431,17 +549,15 @@
return util::make_unique<RawString>(
mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig }));
}
-
return {};
}
bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
bool formatted = true;
if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) {
if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) {
- mDiag->error(DiagMessage(source) << "invalid value for 'formatted'. Must be a boolean");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid value for 'formatted'. Must be a boolean");
return false;
}
}
@@ -449,7 +565,7 @@
bool translateable = mOptions.translatable;
if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
- mDiag->error(DiagMessage(source)
+ mDiag->error(DiagMessage(outResource->source)
<< "invalid value for 'translatable'. Must be a boolean");
return false;
}
@@ -457,81 +573,39 @@
outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString);
if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "not a valid string");
+ mDiag->error(DiagMessage(outResource->source) << "not a valid string");
return false;
}
- if (formatted && translateable) {
- if (String* stringValue = valueCast<String>(outResource->value.get())) {
+ if (String* stringValue = valueCast<String>(outResource->value.get())) {
+ stringValue->setTranslateable(translateable);
+
+ if (formatted && translateable) {
if (!util::verifyJavaStringFormat(*stringValue->value)) {
- mDiag->error(DiagMessage(source)
+ mDiag->error(DiagMessage(outResource->source)
<< "multiple substitutions specified in non-positional format; "
"did you mean to add the formatted=\"false\" attribute?");
return false;
}
}
- }
- return true;
-}
-bool ResourceParser::parseColor(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
- outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
- if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "invalid color");
- return false;
- }
- return true;
-}
-
-bool ResourceParser::parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
- uint32_t typeMask = 0;
- switch (outResource->name.type) {
- case ResourceType::kInteger:
- typeMask |= android::ResTable_map::TYPE_INTEGER;
- break;
-
- case ResourceType::kFraction:
- // fallthrough
- case ResourceType::kDimen:
- typeMask |= android::ResTable_map::TYPE_DIMENSION
- | android::ResTable_map::TYPE_FLOAT
- | android::ResTable_map::TYPE_FRACTION;
- break;
-
- case ResourceType::kBool:
- typeMask |= android::ResTable_map::TYPE_BOOLEAN;
- break;
-
- default:
- assert(false);
- break;
- }
-
- outResource->value = parseXml(parser, typeMask, kNoRawString);
- if (!outResource->value) {
- mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type);
- return false;
+ } else if (StyledString* stringValue = valueCast<StyledString>(outResource->value.get())) {
+ stringValue->setTranslateable(translateable);
}
return true;
}
bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<public> must have a 'type' attribute");
+ mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
- << "' in <public>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value() << "' in <public>");
return false;
}
@@ -543,8 +617,8 @@
maybeId.value().size(), &val);
ResourceId resourceId(val.data);
if (!result || !resourceId.isValid()) {
- mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
- << "' in <public>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource ID '" << maybeId.value() << "' in <public>");
return false;
}
outResource->id = resourceId;
@@ -560,24 +634,24 @@
}
bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<public-group> must have a 'type' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<public-group> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
- << "' in <public-group>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value() << "' in <public-group>");
return false;
}
Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id");
if (!maybeId) {
- mDiag->error(DiagMessage(source) << "<public-group> must have a 'first-id' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<public-group> must have a 'first-id' attribute");
return false;
}
@@ -586,8 +660,8 @@
maybeId.value().size(), &val);
ResourceId nextId(val.data);
if (!result || !nextId.isValid()) {
- mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value()
- << "' in <public-group>");
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource ID '" << maybeId.value() << "' in <public-group>");
return false;
}
@@ -646,18 +720,17 @@
}
bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
-
Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type");
if (!maybeType) {
- mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a "
- "'type' attribute");
+ mDiag->error(DiagMessage(outResource->source)
+ << "<" << parser->getElementName() << "> must have a 'type' attribute");
return false;
}
const ResourceType* parsedType = parseResourceType(maybeType.value());
if (!parsedType) {
- mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value()
+ mDiag->error(DiagMessage(outResource->source)
+ << "invalid resource type '" << maybeType.value()
<< "' in <" << parser->getElementName() << ">");
return false;
}
@@ -682,40 +755,15 @@
return false;
}
-static uint32_t parseFormatType(const StringPiece16& piece) {
- if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE;
- else if (piece == u"string") return android::ResTable_map::TYPE_STRING;
- else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER;
- else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN;
- else if (piece == u"color") return android::ResTable_map::TYPE_COLOR;
- else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT;
- else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
- else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION;
- else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM;
- else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS;
- return 0;
-}
-
-static uint32_t parseFormatAttribute(const StringPiece16& str) {
- uint32_t mask = 0;
- for (StringPiece16 part : util::tokenize(str, u'|')) {
- StringPiece16 trimmedPart = util::trimWhitespace(part);
- uint32_t type = parseFormatType(trimmedPart);
- if (type == 0) {
- return 0;
- }
- mask |= type;
- }
- return mask;
-}
bool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) {
- outResource->source = mSource.withLine(parser->getLineNumber());
return parseAttrImpl(parser, outResource, false);
}
bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
bool weak) {
+ outResource->name.type = ResourceType::kAttr;
+
uint32_t typeMask = 0;
Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format");
@@ -949,7 +997,8 @@
}
bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
+ outResource->name.type = ResourceType::kStyle;
+
std::unique_ptr<Style> style = util::make_unique<Style>();
Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent");
@@ -959,7 +1008,7 @@
std::string errStr;
style->parent = ResourceUtils::parseStyleParentReference(maybeParent.value(), &errStr);
if (!style->parent) {
- mDiag->error(DiagMessage(source) << errStr);
+ mDiag->error(DiagMessage(outResource->source) << errStr);
return false;
}
@@ -1007,9 +1056,22 @@
return true;
}
-bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource,
- uint32_t typeMask) {
- const Source source = mSource.withLine(parser->getLineNumber());
+bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_ANY);
+}
+
+bool ResourceParser::parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_INTEGER);
+}
+
+bool ResourceParser::parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource) {
+ return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_STRING);
+}
+
+bool ResourceParser::parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource,
+ const uint32_t typeMask) {
+ outResource->name.type = ResourceType::kArray;
+
std::unique_ptr<Array> array = util::make_unique<Array>();
bool error = false;
@@ -1049,7 +1111,8 @@
}
bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
+ outResource->name.type = ResourceType::kPlurals;
+
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
bool error = false;
@@ -1123,12 +1186,13 @@
}
bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource) {
- const Source source = mSource.withLine(parser->getLineNumber());
- std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+ outResource->name.type = ResourceType::kStyleable;
// Declare-styleable is kPrivate by default, because it technically only exists in R.java.
outResource->symbolState = SymbolState::kPublic;
+ std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+
std::u16string comment;
bool error = false;
const size_t depth = parser->getDepth();
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 04db577..9ad749e 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -34,11 +34,11 @@
struct ResourceParserOptions {
/**
- * Optional product name by which to filter resources.
+ * Optional product names by which to filter resources.
* This is like a preprocessor definition in that we strip out resources
* that don't match before we compile them.
*/
- Maybe<std::u16string> product;
+ std::vector<std::u16string> products;
/**
* Whether the default setting for this parser is to allow translation.
@@ -78,9 +78,11 @@
const bool allowRawValue);
bool parseResources(xml::XmlPullParser* parser);
+ bool parseResource(xml::XmlPullParser* parser, ParsedResource* outResource);
+
+ bool parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t format);
bool parseString(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parseColor(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource);
+
bool parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource);
@@ -93,9 +95,15 @@
bool parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource);
bool parseStyleItem(xml::XmlPullParser* parser, Style* style);
bool parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource);
- bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
+ bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask);
bool parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource);
+ bool shouldStripResource(const ResourceNameRef& name,
+ const Maybe<std::u16string>& product) const;
+
IDiagnostics* mDiag;
ResourceTable* mTable;
Source mSource;
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 84f67c6..8d10ba1 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -48,11 +48,11 @@
}
::testing::AssertionResult testParse(const StringPiece& str,
- Maybe<std::u16string> product = {}) {
+ std::initializer_list<std::u16string> products = {}) {
std::stringstream input(kXmlPreamble);
input << "<resources>\n" << str << "\n</resources>" << std::endl;
ResourceParserOptions parserOptions;
- parserOptions.product = product;
+ parserOptions.products = products;
ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {},
parserOptions);
xml::XmlPullParser xmlParser(input);
@@ -215,7 +215,7 @@
ASSERT_TRUE(testParse(input));
Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo");
- ASSERT_NE(flagAttr, nullptr);
+ ASSERT_NE(nullptr, flagAttr);
EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS);
ASSERT_EQ(flagAttr->symbols.size(), 3u);
@@ -233,7 +233,7 @@
std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr,
u"baz|bat");
- ASSERT_NE(flagValue, nullptr);
+ ASSERT_NE(nullptr, flagValue);
EXPECT_EQ(flagValue->value.data, 1u | 2u);
}
@@ -255,7 +255,7 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value());
@@ -276,7 +276,7 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value());
@@ -288,7 +288,7 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value());
@@ -302,7 +302,7 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
ASSERT_EQ(1u, style->entries.size());
EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value());
}
@@ -312,7 +312,7 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_ASSERT_TRUE(style->parent);
AAPT_ASSERT_TRUE(style->parent.value().name);
EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo"));
@@ -324,11 +324,21 @@
ASSERT_TRUE(testParse(input));
Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar");
- ASSERT_NE(style, nullptr);
+ ASSERT_NE(nullptr, style);
AAPT_EXPECT_FALSE(style->parent);
EXPECT_FALSE(style->parentInferred);
}
+TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
+ std::string input = R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
+ ASSERT_TRUE(testParse(input));
+
+ Style* style = test::getValue<Style>(&mTable, u"@style/foo");
+ ASSERT_NE(nullptr, style);
+ AAPT_ASSERT_TRUE(style->parent);
+ EXPECT_TRUE(style->parent.value().privateReference);
+}
+
TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
std::string input = "<string name=\"foo\">@+id/bar</string>";
ASSERT_TRUE(testParse(input));
@@ -504,11 +514,15 @@
}
TEST_F(ResourceParserTest, FilterProductsThatDontMatch) {
- std::string input = "<string name=\"foo\" product=\"phone\">hi</string>\n"
- "<string name=\"foo\" product=\"no-sdcard\">ho</string>\n"
- "<string name=\"bar\" product=\"\">wee</string>\n"
- "<string name=\"baz\">woo</string>\n";
- ASSERT_TRUE(testParse(input, std::u16string(u"no-sdcard")));
+ std::string input = R"EOF(
+ <string name="foo" product="phone">hi</string>
+ <string name="foo" product="no-sdcard">ho</string>
+ <string name="bar" product="">wee</string>
+ <string name="baz">woo</string>
+ <string name="bit" product="phablet">hoot</string>
+ <string name="bot" product="default">yes</string>
+ )EOF";
+ ASSERT_TRUE(testParse(input, { std::u16string(u"no-sdcard"), std::u16string(u"phablet") }));
String* fooStr = test::getValue<String>(&mTable, u"@string/foo");
ASSERT_NE(nullptr, fooStr);
@@ -516,11 +530,25 @@
EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bar"));
EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/baz"));
+ EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bit"));
+ EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bot"));
+}
+
+TEST_F(ResourceParserTest, FilterProductsThatBothMatchInOrder) {
+ std::string input = R"EOF(
+ <string name="foo" product="phone">phone</string>
+ <string name="foo" product="default">default</string>
+ )EOF";
+ ASSERT_TRUE(testParse(input, { std::u16string(u"phone") }));
+
+ String* foo = test::getValue<String>(&mTable, u"@string/foo");
+ ASSERT_NE(nullptr, foo);
+ EXPECT_EQ(std::u16string(u"phone"), *foo->value);
}
TEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) {
std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n";
- ASSERT_FALSE(testParse(input, std::u16string(u"phone")));
+ ASSERT_FALSE(testParse(input, { std::u16string(u"phone") }));
}
TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
@@ -575,4 +603,14 @@
EXPECT_EQ(SymbolState::kUndefined, entry->symbolStatus.state);
}
+TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
+ std::string input = R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
+ ASSERT_TRUE(testParse(input));
+
+ BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo");
+ ASSERT_NE(nullptr, val);
+
+ EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 36c3e70..1dc123e 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -176,10 +176,10 @@
/*
* Style parent's are a bit different. We accept the following formats:
*
- * @[package:]style/<entry>
- * ?[package:]style/<entry>
- * <package>:[style/]<entry>
- * [package:style/]<entry>
+ * @[[*]package:]style/<entry>
+ * ?[[*]package:]style/<entry>
+ * <[*]package>:[style/]<entry>
+ * [[*]package:style/]<entry>
*/
Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) {
if (str.empty()) {
@@ -195,10 +195,11 @@
if (name.data()[0] == u'@' || name.data()[0] == u'?') {
hasLeadingIdentifiers = true;
name = name.substr(1, name.size() - 1);
- if (name.data()[0] == u'*') {
- privateRef = true;
- name = name.substr(1, name.size() - 1);
- }
+ }
+
+ if (name.data()[0] == u'*') {
+ privateRef = true;
+ name = name.substr(1, name.size() - 1);
}
ResourceNameRef ref;
diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp
index 4bbfc32..88efa67 100644
--- a/tools/aapt2/ResourceUtils_test.cpp
+++ b/tools/aapt2/ResourceUtils_test.cpp
@@ -157,6 +157,11 @@
ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr);
AAPT_ASSERT_TRUE(ref);
EXPECT_EQ(ref.value().name.value(), kStyleFooName);
+
+ ref = ResourceUtils::parseStyleParentReference(u"*android:style/foo", &errStr);
+ AAPT_ASSERT_TRUE(ref);
+ EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName);
+ EXPECT_TRUE(ref.value().privateReference);
}
} // namespace aapt
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 04c375f..b93e6d8 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -36,10 +36,6 @@
visitor->visit(static_cast<Derived*>(this));
}
-bool Value::isWeak() const {
- return false;
-}
-
RawString::RawString(const StringPool::Ref& ref) : value(ref) {
}
@@ -101,10 +97,6 @@
}
}
-bool Id::isWeak() const {
- return true;
-}
-
bool Id::flatten(android::Res_value* out) const {
out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
out->data = util::hostToDevice32(0);
@@ -119,7 +111,15 @@
*out << "(id)";
}
-String::String(const StringPool::Ref& ref) : value(ref) {
+String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
+}
+
+void String::setTranslateable(bool val) {
+ mTranslateable = val;
+}
+
+bool String::isTranslateable() const {
+ return mTranslateable;
}
bool String::flatten(android::Res_value* outValue) const {
@@ -144,7 +144,15 @@
*out << "(string) \"" << *value << "\"";
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
+}
+
+void StyledString::setTranslateable(bool val) {
+ mTranslateable = val;
+}
+
+bool StyledString::isTranslateable() const {
+ return mTranslateable;
}
bool StyledString::flatten(android::Res_value* outValue) const {
@@ -238,13 +246,10 @@
}
Attribute::Attribute(bool w, uint32_t t) :
- weak(w), typeMask(t),
+ typeMask(t),
minInt(std::numeric_limits<int32_t>::min()),
maxInt(std::numeric_limits<int32_t>::max()) {
-}
-
-bool Attribute::isWeak() const {
- return weak;
+ mWeak = w;
}
Attribute* Attribute::clone(StringPool* /*newPool*/) const {
@@ -359,7 +364,7 @@
<< "]";
}
- if (weak) {
+ if (isWeak()) {
*out << " [weak]";
}
}
@@ -457,6 +462,9 @@
void Style::print(std::ostream* out) const {
*out << "(style) ";
if (parent && parent.value().name) {
+ if (parent.value().privateReference) {
+ *out << "*";
+ }
*out << parent.value().name.value();
}
*out << " ["
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index a038282..8e317db 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -43,9 +43,15 @@
/**
* Whether this value is weak and can be overridden without
- * warning or error. Default for base class is false.
+ * warning or error. Default is false.
*/
- virtual bool isWeak() const;
+ bool isWeak() const {
+ return mWeak;
+ }
+
+ void setWeak(bool val) {
+ mWeak = val;
+ }
/**
* Returns the source where this value was defined.
@@ -95,6 +101,7 @@
protected:
Source mSource;
std::u16string mComment;
+ bool mWeak = false;
};
/**
@@ -159,7 +166,7 @@
* An ID resource. Has no real value, just a place holder.
*/
struct Id : public BaseItem<Id> {
- bool isWeak() const override;
+ Id() { mWeak = true; }
bool flatten(android::Res_value* out) const override;
Id* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
@@ -185,9 +192,17 @@
String(const StringPool::Ref& ref);
+ // Whether the string is marked as translateable. This does not persist when flattened.
+ // It is only used during compilation phase.
+ void setTranslateable(bool val);
+ bool isTranslateable() const;
+
bool flatten(android::Res_value* outValue) const override;
String* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
+
+private:
+ bool mTranslateable;
};
struct StyledString : public BaseItem<StyledString> {
@@ -195,9 +210,17 @@
StyledString(const StringPool::StyleRef& ref);
+ // Whether the string is marked as translateable. This does not persist when flattened.
+ // It is only used during compilation phase.
+ void setTranslateable(bool val);
+ bool isTranslateable() const;
+
bool flatten(android::Res_value* outValue) const override;
StyledString* clone(StringPool* newPool) const override;
void print(std::ostream* out) const override;
+
+private:
+ bool mTranslateable;
};
struct FileReference : public BaseItem<FileReference> {
@@ -232,7 +255,6 @@
uint32_t value;
};
- bool weak;
uint32_t typeMask;
int32_t minInt;
int32_t maxInt;
@@ -240,7 +262,6 @@
Attribute(bool w, uint32_t t = 0u);
- bool isWeak() const override;
Attribute* clone(StringPool* newPool) const override;
void printMask(std::ostream* out) const;
void print(std::ostream* out) const override;
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index 90e35d5..b3b0f65 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -21,6 +21,7 @@
#include "ResourceTable.h"
#include "compile/IdAssigner.h"
#include "compile/Png.h"
+#include "compile/PseudolocaleGenerator.h"
#include "compile/XmlIdCollector.h"
#include "flatten/Archive.h"
#include "flatten/FileExportWriter.h"
@@ -104,7 +105,8 @@
struct CompileOptions {
std::string outputPath;
Maybe<std::string> resDir;
- Maybe<std::u16string> product;
+ std::vector<std::u16string> products;
+ bool pseudolocalize = false;
bool verbose = false;
};
@@ -189,7 +191,7 @@
xml::XmlPullParser xmlParser(fin);
ResourceParserOptions parserOptions;
- parserOptions.product = options.product;
+ parserOptions.products = options.products;
// If the filename includes donottranslate, then the default translatable is false.
parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos;
@@ -203,6 +205,16 @@
fin.close();
}
+ if (options.pseudolocalize) {
+ // Generate pseudo-localized strings (en-XA and ar-XB).
+ // These are created as weak symbols, and are only generated from default configuration
+ // strings and plurals.
+ PseudolocaleGenerator pseudolocaleGenerator;
+ if (!pseudolocaleGenerator.consume(context, &table)) {
+ return false;
+ }
+ }
+
// Ensure we have the compilation package at least.
table.createPackage(context->getCompilationPackage());
@@ -418,18 +430,23 @@
int compile(const std::vector<StringPiece>& args) {
CompileOptions options;
- Maybe<std::string> product;
+ Maybe<std::string> productList;
Flags flags = Flags()
.requiredFlag("-o", "Output path", &options.outputPath)
- .optionalFlag("--product", "Product type to compile", &product)
+ .optionalFlag("--product", "Comma separated list of product types to compile",
+ &productList)
.optionalFlag("--dir", "Directory to scan for resources", &options.resDir)
+ .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales "
+ "(en-XA and ar-XB)", &options.pseudolocalize)
.optionalSwitch("-v", "Enables verbose logging", &options.verbose);
if (!flags.parse("aapt2 compile", args, &std::cerr)) {
return 1;
}
- if (product) {
- options.product = util::utf8ToUtf16(product.value());
+ if (productList) {
+ for (StringPiece part : util::tokenize<char>(productList.value(), ',')) {
+ options.products.push_back(util::utf8ToUtf16(part));
+ }
}
CompileContext context;
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
new file mode 100644
index 0000000..2963d13
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ResourceTable.h"
+#include "ResourceValues.h"
+#include "ValueVisitor.h"
+#include "compile/PseudolocaleGenerator.h"
+#include "compile/Pseudolocalizer.h"
+#include "util/Comparators.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ StringPool* pool) {
+ Pseudolocalizer localizer(method);
+
+ const StringPiece16 originalText = *string->value->str;
+
+ StyleString localized;
+
+ // Copy the spans. We will update their offsets when we localize.
+ localized.spans.reserve(string->value->spans.size());
+ for (const StringPool::Span& span : string->value->spans) {
+ localized.spans.push_back(Span{ *span.name, span.firstChar, span.lastChar });
+ }
+
+ // The ranges are all represented with a single value. This is the start of one range and
+ // end of another.
+ struct Range {
+ size_t start;
+
+ // Once the new string is localized, these are the pointers to the spans to adjust.
+ // Since this struct represents the start of one range and end of another, we have
+ // the two pointers respectively.
+ uint32_t* updateStart;
+ uint32_t* updateEnd;
+ };
+
+ auto cmp = [](const Range& r, size_t index) -> bool {
+ return r.start < index;
+ };
+
+ // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7]
+ // The ranges are the spaces in between. In this example, with a total string length of 9,
+ // the vector represents: (0,1], (2,4], (5,6], (7,9]
+ //
+ std::vector<Range> ranges;
+ ranges.push_back(Range{ 0 });
+ ranges.push_back(Range{ originalText.size() - 1 });
+ for (size_t i = 0; i < string->value->spans.size(); i++) {
+ const StringPool::Span& span = string->value->spans[i];
+
+ // Insert or update the Range marker for the start of this span.
+ auto iter = std::lower_bound(ranges.begin(), ranges.end(), span.firstChar, cmp);
+ if (iter != ranges.end() && iter->start == span.firstChar) {
+ iter->updateStart = &localized.spans[i].firstChar;
+ } else {
+ ranges.insert(iter,
+ Range{ span.firstChar, &localized.spans[i].firstChar, nullptr });
+ }
+
+ // Insert or update the Range marker for the end of this span.
+ iter = std::lower_bound(ranges.begin(), ranges.end(), span.lastChar, cmp);
+ if (iter != ranges.end() && iter->start == span.lastChar) {
+ iter->updateEnd = &localized.spans[i].lastChar;
+ } else {
+ ranges.insert(iter,
+ Range{ span.lastChar, nullptr, &localized.spans[i].lastChar });
+ }
+ }
+
+ localized.str += localizer.start();
+
+ // Iterate over the ranges and localize each section.
+ for (size_t i = 0; i < ranges.size(); i++) {
+ const size_t start = ranges[i].start;
+ size_t len = originalText.size() - start;
+ if (i + 1 < ranges.size()) {
+ len = ranges[i + 1].start - start;
+ }
+
+ if (ranges[i].updateStart) {
+ *ranges[i].updateStart = localized.str.size();
+ }
+
+ if (ranges[i].updateEnd) {
+ *ranges[i].updateEnd = localized.str.size();
+ }
+
+ localized.str += localizer.text(originalText.substr(start, len));
+ }
+
+ localized.str += localizer.end();
+
+ std::unique_ptr<StyledString> localizedString = util::make_unique<StyledString>(
+ pool->makeRef(localized));
+ localizedString->setSource(string->getSource());
+ return localizedString;
+}
+
+namespace {
+
+struct Visitor : public RawValueVisitor {
+ StringPool* mPool;
+ Pseudolocalizer::Method mMethod;
+ Pseudolocalizer mLocalizer;
+
+ // Either value or item will be populated upon visiting the value.
+ std::unique_ptr<Value> mValue;
+ std::unique_ptr<Item> mItem;
+
+ Visitor(StringPool* pool, Pseudolocalizer::Method method) :
+ mPool(pool), mMethod(method), mLocalizer(method) {
+ }
+
+ void visit(Array* array) override {
+ std::unique_ptr<Array> localized = util::make_unique<Array>();
+ localized->items.resize(array->items.size());
+ for (size_t i = 0; i < array->items.size(); i++) {
+ Visitor subVisitor(mPool, mMethod);
+ array->items[i]->accept(&subVisitor);
+ if (subVisitor.mItem) {
+ localized->items[i] = std::move(subVisitor.mItem);
+ } else {
+ localized->items[i] = std::unique_ptr<Item>(array->items[i]->clone(mPool));
+ }
+ }
+ localized->setSource(array->getSource());
+ localized->setWeak(true);
+ mValue = std::move(localized);
+ }
+
+ void visit(Plural* plural) override {
+ std::unique_ptr<Plural> localized = util::make_unique<Plural>();
+ for (size_t i = 0; i < plural->values.size(); i++) {
+ Visitor subVisitor(mPool, mMethod);
+ if (plural->values[i]) {
+ plural->values[i]->accept(&subVisitor);
+ if (subVisitor.mValue) {
+ localized->values[i] = std::move(subVisitor.mItem);
+ } else {
+ localized->values[i] = std::unique_ptr<Item>(plural->values[i]->clone(mPool));
+ }
+ }
+ }
+ localized->setSource(plural->getSource());
+ localized->setWeak(true);
+ mValue = std::move(localized);
+ }
+
+ void visit(String* string) override {
+ if (!string->isTranslateable()) {
+ return;
+ }
+
+ std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) +
+ mLocalizer.end();
+ std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result));
+ localized->setSource(string->getSource());
+ localized->setWeak(true);
+ mItem = std::move(localized);
+ }
+
+ void visit(StyledString* string) override {
+ if (!string->isTranslateable()) {
+ return;
+ }
+
+ mItem = pseudolocalizeStyledString(string, mMethod, mPool);
+ mItem->setWeak(true);
+ }
+};
+
+ConfigDescription modifyConfigForPseudoLocale(const ConfigDescription& base,
+ Pseudolocalizer::Method m) {
+ ConfigDescription modified = base;
+ switch (m) {
+ case Pseudolocalizer::Method::kAccent:
+ modified.language[0] = 'e';
+ modified.language[1] = 'n';
+ modified.country[0] = 'X';
+ modified.country[1] = 'A';
+ break;
+
+ case Pseudolocalizer::Method::kBidi:
+ modified.language[0] = 'a';
+ modified.language[1] = 'r';
+ modified.country[0] = 'X';
+ modified.country[1] = 'B';
+ break;
+ default:
+ break;
+ }
+ return modified;
+}
+
+void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues,
+ Pseudolocalizer::Method method, StringPool* pool, Value* value) {
+ Visitor visitor(pool, method);
+ value->accept(&visitor);
+
+ std::unique_ptr<Value> localizedValue;
+ if (visitor.mValue) {
+ localizedValue = std::move(visitor.mValue);
+ } else if (visitor.mItem) {
+ localizedValue = std::move(visitor.mItem);
+ }
+
+ if (localizedValue) {
+ ConfigDescription pseudolocalizedConfig = modifyConfigForPseudoLocale(ConfigDescription{},
+ method);
+ auto iter = std::lower_bound(configValues->begin(), configValues->end(),
+ pseudolocalizedConfig, cmp::lessThanConfig);
+ if (iter == configValues->end() || iter->config != pseudolocalizedConfig) {
+ // The pseudolocalized config doesn't exist, add it.
+ configValues->insert(iter, ResourceConfigValue{ pseudolocalizedConfig,
+ std::move(localizedValue) });
+ }
+ }
+}
+
+} // namespace
+
+bool PseudolocaleGenerator::consume(IAaptContext* context, ResourceTable* table) {
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ auto iter = std::lower_bound(entry->values.begin(), entry->values.end(),
+ ConfigDescription{}, cmp::lessThanConfig);
+ if (iter != entry->values.end() && iter->config == ConfigDescription{}) {
+ // Only pseudolocalize the default configuration.
+
+ // The iterator will be invalidated, so grab a pointer to the value.
+ Value* originalValue = iter->value.get();
+
+ pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kAccent,
+ &table->stringPool, originalValue);
+ pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kBidi,
+ &table->stringPool, originalValue);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h
new file mode 100644
index 0000000..4fbc516
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
+#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H
+
+#include "StringPool.h"
+#include "compile/Pseudolocalizer.h"
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string,
+ Pseudolocalizer::Method method,
+ StringPool* pool);
+
+struct PseudolocaleGenerator : public IResourceTableConsumer {
+ bool consume(IAaptContext* context, ResourceTable* table) override;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H */
diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
new file mode 100644
index 0000000..4cb6ea2
--- /dev/null
+++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/PseudolocaleGenerator.h"
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) {
+ StringPool pool;
+ StyleString originalStyle;
+ originalStyle.str = u"Hello world!";
+ originalStyle.spans = { Span{ u"b", 2, 3 }, Span{ u"b", 6, 7 }, Span{ u"i", 1, 10 } };
+
+ std::unique_ptr<StyledString> newString = pseudolocalizeStyledString(
+ util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+ Pseudolocalizer::Method::kNone, &pool);
+
+ EXPECT_EQ(originalStyle.str, *newString->value->str);
+ ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+ EXPECT_EQ(2u, newString->value->spans[0].firstChar);
+ EXPECT_EQ(3u, newString->value->spans[0].lastChar);
+ EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[0].name);
+
+ EXPECT_EQ(6u, newString->value->spans[1].firstChar);
+ EXPECT_EQ(7u, newString->value->spans[1].lastChar);
+ EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[1].name);
+
+ EXPECT_EQ(1u, newString->value->spans[2].firstChar);
+ EXPECT_EQ(10u, newString->value->spans[2].lastChar);
+ EXPECT_EQ(std::u16string(u"i"), *newString->value->spans[2].name);
+
+ originalStyle.spans.push_back(Span{ u"em", 0, 11u });
+
+ newString = pseudolocalizeStyledString(
+ util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(),
+ Pseudolocalizer::Method::kAccent, &pool);
+
+ EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str);
+ ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size());
+
+ EXPECT_EQ(3u, newString->value->spans[0].firstChar);
+ EXPECT_EQ(4u, newString->value->spans[0].lastChar);
+
+ EXPECT_EQ(7u, newString->value->spans[1].firstChar);
+ EXPECT_EQ(8u, newString->value->spans[1].lastChar);
+
+ EXPECT_EQ(2u, newString->value->spans[2].firstChar);
+ EXPECT_EQ(11u, newString->value->spans[2].lastChar);
+
+ EXPECT_EQ(1u, newString->value->spans[3].firstChar);
+ EXPECT_EQ(12u, newString->value->spans[3].lastChar);
+}
+
+TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) {
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .addString(u"@android:string/one", u"one")
+ .addString(u"@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), u"two")
+ .addString(u"@android:string/three", u"three")
+ .addString(u"@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"),
+ u"three")
+ .addString(u"@android:string/four", u"four")
+ .build();
+
+ String* val = test::getValue<String>(table.get(), u"@android:string/four");
+ val->setTranslateable(false);
+
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+ PseudolocaleGenerator generator;
+ ASSERT_TRUE(generator.consume(context.get(), table.get()));
+
+ // Normal pseudolocalization should take place.
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one",
+ test::parseConfigOrDie("ar-rXB")));
+
+ // No default config for android:string/two, so no pseudlocales should exist.
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two",
+ test::parseConfigOrDie("ar-rXB")));
+
+
+ // Check that we didn't override manual pseudolocalization.
+ val = test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ test::parseConfigOrDie("en-rXA"));
+ ASSERT_NE(nullptr, val);
+ EXPECT_EQ(std::u16string(u"three"), *val->value);
+
+ ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/three",
+ test::parseConfigOrDie("ar-rXB")));
+
+ // Check that four's translateable marker was honored.
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ test::parseConfigOrDie("en-rXA")));
+ ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four",
+ test::parseConfigOrDie("ar-rXB")));
+
+}
+
+} // namespace aapt
+
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
new file mode 100644
index 0000000..eae52d7
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+namespace aapt {
+
+// String basis to generate expansion
+static const std::u16string k_expansion_string = u"one two three "
+ "four five six seven eight nine ten eleven twelve thirteen "
+ "fourteen fiveteen sixteen seventeen nineteen twenty";
+
+// Special unicode characters to override directionality of the words
+static const std::u16string k_rlm = u"\u200f";
+static const std::u16string k_rlo = u"\u202e";
+static const std::u16string k_pdf = u"\u202c";
+
+// Placeholder marks
+static const std::u16string k_placeholder_open = u"\u00bb";
+static const std::u16string k_placeholder_close = u"\u00ab";
+
+static const char16_t k_arg_start = u'{';
+static const char16_t k_arg_end = u'}';
+
+class PseudoMethodNone : public PseudoMethodImpl {
+public:
+ std::u16string text(const StringPiece16& text) override { return text.toString(); }
+ std::u16string placeholder(const StringPiece16& text) override { return text.toString(); }
+};
+
+class PseudoMethodBidi : public PseudoMethodImpl {
+public:
+ std::u16string text(const StringPiece16& text) override;
+ std::u16string placeholder(const StringPiece16& text) override;
+};
+
+class PseudoMethodAccent : public PseudoMethodImpl {
+public:
+ PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {}
+ std::u16string start() override;
+ std::u16string end() override;
+ std::u16string text(const StringPiece16& text) override;
+ std::u16string placeholder(const StringPiece16& text) override;
+private:
+ size_t mDepth;
+ size_t mWordCount;
+ size_t mLength;
+};
+
+Pseudolocalizer::Pseudolocalizer(Method method) : mLastDepth(0) {
+ setMethod(method);
+}
+
+void Pseudolocalizer::setMethod(Method method) {
+ switch (method) {
+ case Method::kNone:
+ mImpl = util::make_unique<PseudoMethodNone>();
+ break;
+ case Method::kAccent:
+ mImpl = util::make_unique<PseudoMethodAccent>();
+ break;
+ case Method::kBidi:
+ mImpl = util::make_unique<PseudoMethodBidi>();
+ break;
+ }
+}
+
+std::u16string Pseudolocalizer::text(const StringPiece16& text) {
+ std::u16string out;
+ size_t depth = mLastDepth;
+ size_t lastpos, pos;
+ const size_t length = text.size();
+ const char16_t* str = text.data();
+ bool escaped = false;
+ for (lastpos = pos = 0; pos < length; pos++) {
+ char16_t c = str[pos];
+ if (escaped) {
+ escaped = false;
+ continue;
+ }
+ if (c == '\'') {
+ escaped = true;
+ continue;
+ }
+
+ if (c == k_arg_start) {
+ depth++;
+ } else if (c == k_arg_end && depth) {
+ depth--;
+ }
+
+ if (mLastDepth != depth || pos == length - 1) {
+ bool pseudo = ((mLastDepth % 2) == 0);
+ size_t nextpos = pos;
+ if (!pseudo || depth == mLastDepth) {
+ nextpos++;
+ }
+ size_t size = nextpos - lastpos;
+ if (size) {
+ std::u16string chunk = text.substr(lastpos, size).toString();
+ if (pseudo) {
+ chunk = mImpl->text(chunk);
+ } else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) {
+ chunk = mImpl->placeholder(chunk);
+ }
+ out.append(chunk);
+ }
+ if (pseudo && depth < mLastDepth) { // End of message
+ out.append(mImpl->end());
+ } else if (!pseudo && depth > mLastDepth) { // Start of message
+ out.append(mImpl->start());
+ }
+ lastpos = nextpos;
+ mLastDepth = depth;
+ }
+ }
+ return out;
+}
+
+static const char16_t* pseudolocalizeChar(const char16_t c) {
+ switch (c) {
+ case 'a': return u"\u00e5";
+ case 'b': return u"\u0253";
+ case 'c': return u"\u00e7";
+ case 'd': return u"\u00f0";
+ case 'e': return u"\u00e9";
+ case 'f': return u"\u0192";
+ case 'g': return u"\u011d";
+ case 'h': return u"\u0125";
+ case 'i': return u"\u00ee";
+ case 'j': return u"\u0135";
+ case 'k': return u"\u0137";
+ case 'l': return u"\u013c";
+ case 'm': return u"\u1e3f";
+ case 'n': return u"\u00f1";
+ case 'o': return u"\u00f6";
+ case 'p': return u"\u00fe";
+ case 'q': return u"\u0051";
+ case 'r': return u"\u0155";
+ case 's': return u"\u0161";
+ case 't': return u"\u0163";
+ case 'u': return u"\u00fb";
+ case 'v': return u"\u0056";
+ case 'w': return u"\u0175";
+ case 'x': return u"\u0445";
+ case 'y': return u"\u00fd";
+ case 'z': return u"\u017e";
+ case 'A': return u"\u00c5";
+ case 'B': return u"\u03b2";
+ case 'C': return u"\u00c7";
+ case 'D': return u"\u00d0";
+ case 'E': return u"\u00c9";
+ case 'G': return u"\u011c";
+ case 'H': return u"\u0124";
+ case 'I': return u"\u00ce";
+ case 'J': return u"\u0134";
+ case 'K': return u"\u0136";
+ case 'L': return u"\u013b";
+ case 'M': return u"\u1e3e";
+ case 'N': return u"\u00d1";
+ case 'O': return u"\u00d6";
+ case 'P': return u"\u00de";
+ case 'Q': return u"\u0071";
+ case 'R': return u"\u0154";
+ case 'S': return u"\u0160";
+ case 'T': return u"\u0162";
+ case 'U': return u"\u00db";
+ case 'V': return u"\u03bd";
+ case 'W': return u"\u0174";
+ case 'X': return u"\u00d7";
+ case 'Y': return u"\u00dd";
+ case 'Z': return u"\u017d";
+ case '!': return u"\u00a1";
+ case '?': return u"\u00bf";
+ case '$': return u"\u20ac";
+ default: return NULL;
+ }
+}
+
+static bool isPossibleNormalPlaceholderEnd(const char16_t c) {
+ switch (c) {
+ case 's': return true;
+ case 'S': return true;
+ case 'c': return true;
+ case 'C': return true;
+ case 'd': return true;
+ case 'o': return true;
+ case 'x': return true;
+ case 'X': return true;
+ case 'f': return true;
+ case 'e': return true;
+ case 'E': return true;
+ case 'g': return true;
+ case 'G': return true;
+ case 'a': return true;
+ case 'A': return true;
+ case 'b': return true;
+ case 'B': return true;
+ case 'h': return true;
+ case 'H': return true;
+ case '%': return true;
+ case 'n': return true;
+ default: return false;
+ }
+}
+
+static std::u16string pseudoGenerateExpansion(const unsigned int length) {
+ std::u16string result = k_expansion_string;
+ const char16_t* s = result.data();
+ if (result.size() < length) {
+ result += u" ";
+ result += pseudoGenerateExpansion(length - result.size());
+ } else {
+ int ext = 0;
+ // Should contain only whole words, so looking for a space
+ for (unsigned int i = length + 1; i < result.size(); ++i) {
+ ++ext;
+ if (s[i] == ' ') {
+ break;
+ }
+ }
+ result = result.substr(0, length + ext);
+ }
+ return result;
+}
+
+std::u16string PseudoMethodAccent::start() {
+ std::u16string result;
+ if (mDepth == 0) {
+ result = u"[";
+ }
+ mWordCount = mLength = 0;
+ mDepth++;
+ return result;
+}
+
+std::u16string PseudoMethodAccent::end() {
+ std::u16string result;
+ if (mLength) {
+ result += u" ";
+ result += pseudoGenerateExpansion(mWordCount > 3 ? mLength : mLength / 2);
+ }
+ mWordCount = mLength = 0;
+ mDepth--;
+ if (mDepth == 0) {
+ result += u"]";
+ }
+ return result;
+}
+
+/**
+ * Converts characters so they look like they've been localized.
+ *
+ * Note: This leaves placeholder syntax untouched.
+ */
+std::u16string PseudoMethodAccent::text(const StringPiece16& source)
+{
+ const char16_t* s = source.data();
+ std::u16string result;
+ const size_t I = source.size();
+ bool lastspace = true;
+ for (size_t i = 0; i < I; i++) {
+ char16_t c = s[i];
+ if (c == '%') {
+ // Placeholder syntax, no need to pseudolocalize
+ std::u16string chunk;
+ bool end = false;
+ chunk.append(&c, 1);
+ while (!end && i < I) {
+ ++i;
+ c = s[i];
+ chunk.append(&c, 1);
+ if (isPossibleNormalPlaceholderEnd(c)) {
+ end = true;
+ } else if (c == 't') {
+ ++i;
+ c = s[i];
+ chunk.append(&c, 1);
+ end = true;
+ }
+ }
+ // Treat chunk as a placeholder unless it ends with %.
+ result += ((c == '%') ? chunk : placeholder(chunk));
+ } else if (c == '<' || c == '&') {
+ // html syntax, no need to pseudolocalize
+ bool tag_closed = false;
+ while (!tag_closed && i < I) {
+ if (c == '&') {
+ std::u16string escapeText;
+ escapeText.append(&c, 1);
+ bool end = false;
+ size_t htmlCodePos = i;
+ while (!end && htmlCodePos < I) {
+ ++htmlCodePos;
+ c = s[htmlCodePos];
+ escapeText.append(&c, 1);
+ // Valid html code
+ if (c == ';') {
+ end = true;
+ i = htmlCodePos;
+ }
+ // Wrong html code
+ else if (!((c == '#' ||
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9')))) {
+ end = true;
+ }
+ }
+ result += escapeText;
+ if (escapeText != u"<") {
+ tag_closed = true;
+ }
+ continue;
+ }
+ if (c == '>') {
+ tag_closed = true;
+ result.append(&c, 1);
+ continue;
+ }
+ result.append(&c, 1);
+ i++;
+ c = s[i];
+ }
+ } else {
+ // This is a pure text that should be pseudolocalized
+ const char16_t* p = pseudolocalizeChar(c);
+ if (p != nullptr) {
+ result += p;
+ } else {
+ bool space = util::isspace16(c);
+ if (lastspace && !space) {
+ mWordCount++;
+ }
+ lastspace = space;
+ result.append(&c, 1);
+ }
+ // Count only pseudolocalizable chars and delimiters
+ mLength++;
+ }
+ }
+ return result;
+}
+
+std::u16string PseudoMethodAccent::placeholder(const StringPiece16& source) {
+ // Surround a placeholder with brackets
+ return k_placeholder_open + source.toString() + k_placeholder_close;
+}
+
+std::u16string PseudoMethodBidi::text(const StringPiece16& source) {
+ const char16_t* s = source.data();
+ std::u16string result;
+ bool lastspace = true;
+ bool space = true;
+ for (size_t i = 0; i < source.size(); i++) {
+ char16_t c = s[i];
+ space = util::isspace16(c);
+ if (lastspace && !space) {
+ // Word start
+ result += k_rlm + k_rlo;
+ } else if (!lastspace && space) {
+ // Word end
+ result += k_pdf + k_rlm;
+ }
+ lastspace = space;
+ result.append(&c, 1);
+ }
+ if (!lastspace) {
+ // End of last word
+ result += k_pdf + k_rlm;
+ }
+ return result;
+}
+
+std::u16string PseudoMethodBidi::placeholder(const StringPiece16& source) {
+ // Surround a placeholder with directionality change sequence
+ return k_rlm + k_rlo + source.toString() + k_pdf + k_rlm;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
new file mode 100644
index 0000000..8818c17
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_COMPILE_PSEUDOLOCALIZE_H
+#define AAPT_COMPILE_PSEUDOLOCALIZE_H
+
+#include "ResourceValues.h"
+#include "StringPool.h"
+#include "util/StringPiece.h"
+
+#include <android-base/macros.h>
+#include <memory>
+
+namespace aapt {
+
+class PseudoMethodImpl {
+public:
+ virtual ~PseudoMethodImpl() {}
+ virtual std::u16string start() { return {}; }
+ virtual std::u16string end() { return {}; }
+ virtual std::u16string text(const StringPiece16& text) = 0;
+ virtual std::u16string placeholder(const StringPiece16& text) = 0;
+};
+
+class Pseudolocalizer {
+public:
+ enum class Method {
+ kNone,
+ kAccent,
+ kBidi,
+ };
+
+ Pseudolocalizer(Method method);
+ void setMethod(Method method);
+ std::u16string start() { return mImpl->start(); }
+ std::u16string end() { return mImpl->end(); }
+ std::u16string text(const StringPiece16& text);
+private:
+ std::unique_ptr<PseudoMethodImpl> mImpl;
+ size_t mLastDepth;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_PSEUDOLOCALIZE_H */
diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp
new file mode 100644
index 0000000..b0bc2c1
--- /dev/null
+++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "compile/Pseudolocalizer.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+// In this context, 'Axis' represents a particular field in the configuration,
+// such as language or density.
+
+static ::testing::AssertionResult simpleHelper(const char* input, const char* expected,
+ Pseudolocalizer::Method method) {
+ Pseudolocalizer pseudo(method);
+ std::string result = util::utf16ToUtf8(
+ pseudo.start() + pseudo.text(util::utf8ToUtf16(input)) + pseudo.end());
+ if (StringPiece(expected) != result) {
+ return ::testing::AssertionFailure() << expected << " != " << result;
+ }
+ return ::testing::AssertionSuccess();
+}
+
+static ::testing::AssertionResult compoundHelper(const char* in1, const char* in2, const char *in3,
+ const char* expected,
+ Pseudolocalizer::Method method) {
+ Pseudolocalizer pseudo(method);
+ std::string result = util::utf16ToUtf8(pseudo.start() +
+ pseudo.text(util::utf8ToUtf16(in1)) +
+ pseudo.text(util::utf8ToUtf16(in2)) +
+ pseudo.text(util::utf8ToUtf16(in3)) +
+ pseudo.end());
+ if (StringPiece(expected) != result) {
+ return ::testing::AssertionFailure() << expected << " != " << result;
+ }
+ return ::testing::AssertionSuccess();
+}
+
+TEST(PseudolocalizerTest, NoPseudolocalization) {
+ EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kNone));
+ EXPECT_TRUE(simpleHelper("Hello, world", "Hello, world", Pseudolocalizer::Method::kNone));
+
+ EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+ "Hello, world", Pseudolocalizer::Method::kNone));
+}
+
+TEST(PseudolocalizerTest, PlaintextAccent) {
+ EXPECT_TRUE(simpleHelper("", "[]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Hello, world",
+ "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper("Hello, %1d",
+ "[Ĥéļļö, »%1d« one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper("Battery %1d%%",
+ "[βåţţéŕý »%1d«%% one two]", Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(compoundHelper("", "", "", "[]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(compoundHelper("Hello,", " world", "",
+ "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PlaintextBidi) {
+ EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper("word",
+ "\xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(" word ",
+ " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(" word ",
+ " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper("hello\n world\n",
+ "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+ " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(compoundHelper("hello", "\n ", " world\n",
+ "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \
+ " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n",
+ Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, SimpleICU) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("{placeholder}", "[»{placeholder}«]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("{USER} is offline",
+ "[»{USER}« îš öƒƒļîñé one two]", Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Copy from {path1} to {path2}",
+ "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(simpleHelper("Today is {1,date} {1,time}",
+ "[Ţöðåý îš »{1,date}« »{1,time}« one two]",
+ Pseudolocalizer::Method::kAccent));
+
+ // Multi-fragment messages
+ EXPECT_TRUE(compoundHelper("{USER}", " ", "is offline",
+ "[»{USER}« îš öƒƒļîñé one two]",
+ Pseudolocalizer::Method::kAccent));
+ EXPECT_TRUE(compoundHelper("Copy from ", "{path1}", " to {path2}",
+ "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, ICUBidi) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("{placeholder}",
+ "\xe2\x80\x8f\xE2\x80\xae{placeholder}\xE2\x80\xac\xe2\x80\x8f",
+ Pseudolocalizer::Method::kBidi));
+ EXPECT_TRUE(simpleHelper(
+ "{COUNT, plural, one {one} other {other}}",
+ "{COUNT, plural, " \
+ "one {\xe2\x80\x8f\xE2\x80\xaeone\xE2\x80\xac\xe2\x80\x8f} " \
+ "other {\xe2\x80\x8f\xE2\x80\xaeother\xE2\x80\xac\xe2\x80\x8f}}",
+ Pseudolocalizer::Method::kBidi));
+}
+
+TEST(PseudolocalizerTest, Escaping) {
+ // Single-fragment messages
+ EXPECT_TRUE(simpleHelper("'{USER'} is offline",
+ "['{ÛŠÉŔ'} îš öƒƒļîñé one two three]",
+ Pseudolocalizer::Method::kAccent));
+
+ // Multi-fragment messages
+ EXPECT_TRUE(compoundHelper("'{USER}", " ", "''is offline",
+ "['{ÛŠÉŔ} ''îš öƒƒļîñé one two three]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, PluralsAndSelects) {
+ EXPECT_TRUE(simpleHelper(
+ "{COUNT, plural, one {Delete a file} other {Delete {COUNT} files}}",
+ "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+ "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper(
+ "Distance is {COUNT, plural, one {# mile} other {# miles}}",
+ "[Ðîšţåñçé îš {COUNT, plural, one {# ḿîļé one two} " \
+ "other {# ḿîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(simpleHelper(
+ "{1, select, female {{1} added you} " \
+ "male {{1} added you} other {{1} added you}}",
+ "[{1, select, female {»{1}« åððéð ýöû one two} " \
+ "male {»{1}« åððéð ýöû one two} other {»{1}« åððéð ýöû one two}}]",
+ Pseudolocalizer::Method::kAccent));
+
+ EXPECT_TRUE(compoundHelper(
+ "{COUNT, plural, one {Delete a file} " \
+ "other {Delete ", "{COUNT}", " files}}",
+ "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \
+ "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, NestedICU) {
+ EXPECT_TRUE(simpleHelper(
+ "{person, select, " \
+ "female {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of her circles.}" \
+ "=1{{person} added you to one of her circles.}" \
+ "other{{person} added you to her # circles.}}}" \
+ "male {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of his circles.}" \
+ "=1{{person} added you to one of his circles.}" \
+ "other{{person} added you to his # circles.}}}" \
+ "other {" \
+ "{num_circles, plural," \
+ "=0{{person} didn't add you to any of their circles.}" \
+ "=1{{person} added you to one of their circles.}" \
+ "other{{person} added you to their # circles.}}}}",
+ "[{person, select, " \
+ "female {" \
+ "{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥéŕ çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥéŕ çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ĥéŕ # çîŕçļéš." \
+ " one two three four}}}" \
+ "male {" \
+ "{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥîš çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥîš çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ĥîš # çîŕçļéš." \
+ " one two three four}}}" \
+ "other {{num_circles, plural," \
+ "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ţĥéîŕ çîŕçļéš." \
+ " one two three four five}" \
+ "=1{»{person}« åððéð ýöû ţö öñé öƒ ţĥéîŕ çîŕçļéš." \
+ " one two three four}" \
+ "other{»{person}« åððéð ýöû ţö ţĥéîŕ # çîŕçļéš." \
+ " one two three four}}}}]",
+ Pseudolocalizer::Method::kAccent));
+}
+
+TEST(PseudolocalizerTest, RedefineMethod) {
+ Pseudolocalizer pseudo(Pseudolocalizer::Method::kAccent);
+ std::u16string result = pseudo.text(u"Hello, ");
+ pseudo.setMethod(Pseudolocalizer::Method::kNone);
+ result += pseudo.text(u"world!");
+ ASSERT_EQ(StringPiece("Ĥéļļö, world!"), util::utf16ToUtf8(result));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/XmlIdCollector_test.cpp b/tools/aapt2/compile/XmlIdCollector_test.cpp
index 45b7af24..a37ea86 100644
--- a/tools/aapt2/compile/XmlIdCollector_test.cpp
+++ b/tools/aapt2/compile/XmlIdCollector_test.cpp
@@ -37,13 +37,13 @@
XmlIdCollector collector;
ASSERT_TRUE(collector.consume(context.get(), doc.get()));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/foo"), 3u }));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/bar"), 3u }));
- EXPECT_EQ(1u, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
+ EXPECT_EQ(1, std::count(doc->file.exportedSymbols.begin(), doc->file.exportedSymbols.end(),
SourcedResourceName{ test::parseNameOrDie(u"@id/car"), 6u }));
}
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index a2f53e1..26d7c2c 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -113,8 +113,7 @@
bool mUseExtendedChunks;
size_t mEntryCount = 0;
- Maybe<uint32_t> mParentIdent;
- Maybe<ResourceNameRef> mParentName;
+ const Reference* mParent = nullptr;
MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer,
StringPool* sourcePool, StringPool* commentPool,
@@ -227,13 +226,8 @@
void visit(Style* style) override {
if (style->parent) {
- bool privateRef = style->parent.value().privateReference && mUseExtendedChunks;
- if (!style->parent.value().id || privateRef) {
- assert(style->parent.value().name && "reference must have a name");
- mParentName = style->parent.value().name;
- } else {
- mParentIdent = style->parent.value().id.value().id;
- }
+ // Parents are treated a bit differently, so record the existence and move on.
+ mParent = &style->parent.value();
}
// Sort the style.
@@ -427,11 +421,16 @@
mOptions.useExtendedChunks);
entry->value->accept(&visitor);
outEntry->count = util::hostToDevice32(visitor.mEntryCount);
- if (visitor.mParentName) {
- mSymbols->addSymbol(visitor.mParentName.value(),
- beforeEntry + offsetof(ResTable_entry_ext, parent));
- } else if (visitor.mParentIdent) {
- outEntry->parent.ident = util::hostToDevice32(visitor.mParentIdent.value());
+ if (visitor.mParent) {
+ const bool forceSymbol = visitor.mParent->privateReference &&
+ mOptions.useExtendedChunks;
+ if (!visitor.mParent->id || forceSymbol) {
+ assert(visitor.mParent->name && "reference must have a name");
+ mSymbols->addSymbol(*visitor.mParent,
+ beforeEntry + offsetof(ResTable_entry_ext, parent));
+ } else {
+ outEntry->parent.ident = util::hostToDevice32(visitor.mParent->id.value().id);
+ }
}
}
return true;
diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp
index c096854..c610bb0 100644
--- a/tools/aapt2/java/ProguardRules.cpp
+++ b/tools/aapt2/java/ProguardRules.cpp
@@ -227,14 +227,14 @@
bool writeKeepSet(std::ostream* out, const KeepSet& keepSet) {
for (const auto& entry : keepSet.mKeepSet) {
for (const Source& source : entry.second) {
- *out << "// Referenced at " << source << "\n";
+ *out << "# Referenced at " << source << "\n";
}
*out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl;
}
for (const auto& entry : keepSet.mKeepMethodSet) {
for (const Source& source : entry.second) {
- *out << "// Referenced at " << source << "\n";
+ *out << "# Referenced at " << source << "\n";
}
*out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl;
}
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index f8e3d03..93a11b9 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -68,6 +68,12 @@
return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str)));
}
+ ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
+ const ConfigDescription& config, const StringPiece16& str) {
+ return addValue(name, id, config,
+ util::make_unique<String>(mTable->stringPool.makeRef(str)));
+ }
+
ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path) {
return addFileReference(name, {}, path);
}
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 21e476f..6b7a63cf 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -585,6 +585,13 @@
source.path = path.toString();
}
source.line = util::deviceToHost32(sourceBlock->line);
+
+ if (Style* style = valueCast<Style>(resourceValue.get())) {
+ // The parent's source is the same as the resource itself, set it here.
+ if (style->parent) {
+ style->parent.value().setSource(source);
+ }
+ }
}
StringPiece16 comment = util::getString(mSourcePool,
diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h
new file mode 100644
index 0000000..b1f9e9d
--- /dev/null
+++ b/tools/aapt2/util/ImmutableMap.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_UTIL_IMMUTABLEMAP_H
+#define AAPT_UTIL_IMMUTABLEMAP_H
+
+#include "util/TypeTraits.h"
+
+#include <utility>
+#include <vector>
+
+namespace aapt {
+
+template <typename TKey, typename TValue>
+class ImmutableMap {
+ static_assert(is_comparable<TKey, TKey>::value, "key is not comparable");
+
+private:
+ std::vector<std::pair<TKey, TValue>> mData;
+
+ explicit ImmutableMap(std::vector<std::pair<TKey, TValue>> data) : mData(std::move(data)) {
+ }
+
+public:
+ using const_iterator = typename decltype(mData)::const_iterator;
+
+ ImmutableMap(ImmutableMap&&) = default;
+ ImmutableMap& operator=(ImmutableMap&&) = default;
+
+ ImmutableMap(const ImmutableMap&) = delete;
+ ImmutableMap& operator=(const ImmutableMap&) = delete;
+
+ static ImmutableMap<TKey, TValue> createPreSorted(
+ std::initializer_list<std::pair<TKey, TValue>> list) {
+ return ImmutableMap(std::vector<std::pair<TKey, TValue>>(list.begin(), list.end()));
+ }
+
+ static ImmutableMap<TKey, TValue> createAndSort(
+ std::initializer_list<std::pair<TKey, TValue>> list) {
+ std::vector<std::pair<TKey, TValue>> data(list.begin(), list.end());
+ std::sort(data.begin(), data.end());
+ return ImmutableMap(std::move(data));
+ }
+
+ template <typename TKey2,
+ typename = typename std::enable_if<is_comparable<TKey, TKey2>::value>::type>
+ const_iterator find(const TKey2& key) const {
+ auto cmp = [](const std::pair<TKey, TValue>& candidate, const TKey2& target) -> bool {
+ return candidate.first < target;
+ };
+
+ const_iterator endIter = end();
+ auto iter = std::lower_bound(mData.begin(), endIter, key, cmp);
+ if (iter == endIter || iter->first == key) {
+ return iter;
+ }
+ return endIter;
+ }
+
+ const_iterator begin() const {
+ return mData.begin();
+ }
+
+ const_iterator end() const {
+ return mData.end();
+ }
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_IMMUTABLEMAP_H */
diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h
new file mode 100644
index 0000000..76c13d6
--- /dev/null
+++ b/tools/aapt2/util/TypeTraits.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_UTIL_TYPETRAITS_H
+#define AAPT_UTIL_TYPETRAITS_H
+
+#include <type_traits>
+
+namespace aapt {
+
+#define DEFINE_HAS_BINARY_OP_TRAIT(name, op) \
+ template <typename T, typename U> \
+ struct name { \
+ template <typename V, typename W> \
+ static constexpr decltype(std::declval<V>() op std::declval<W>(), bool()) test(int) { \
+ return true; \
+ } \
+ template <typename V, typename W> \
+ static constexpr bool test(...) { \
+ return false; \
+ } \
+ static constexpr bool value = test<T, U>(int()); \
+}
+
+DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==);
+DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <);
+
+/**
+ * Type trait that checks if two types can be equated (==) and compared (<).
+ */
+template <typename T, typename U>
+struct is_comparable {
+ static constexpr bool value = has_eq_op<T, U>::value && has_lt_op<T, U>::value;
+};
+
+} // namespace aapt
+
+#endif /* AAPT_UTIL_TYPETRAITS_H */
diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
index 6a68ee2..549074d 100644
--- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java
+++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java
@@ -51,8 +51,10 @@
/**
* Return a list of all currently running services.
+ * @return an array of all currently running services, or <code>null</code> in
+ * case of an exception
*/
- public static String[] listServices() throws RemoteException {
+ public static String[] listServices() {
// actual implementation returns null sometimes, so it's ok
// to return null instead of an empty list.
return null;
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 40437fa..01ee18b 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -76,7 +76,7 @@
@Override
public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
- Rect arg11, Configuration arg12, boolean arg13) throws RemoteException {
+ Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
// TODO Auto-generated method stub
}
@@ -543,6 +543,11 @@
}
@Override
- public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+ public void registerDockedStackListener(IDockedStackListener listener) throws RemoteException {
+ }
+
+ @Override
+ public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
+ throws RemoteException {
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 683c4aa..c8e3d03 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -183,7 +183,7 @@
*/
private static LayoutLog sCurrentLog = sDefaultLog;
- private static final int LAST_SUPPORTED_FEATURE = Features.CHOREOGRAPHER;
+ private static final int LAST_SUPPORTED_FEATURE = Features.THEME_PREVIEW_NAVIGATION_BAR;
@Override
public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index bab25c0..4625de2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -34,7 +34,6 @@
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
@@ -98,7 +97,22 @@
}
@Override
- public int getPackageUid(String packageName, int userHandle) throws NameNotFoundException {
+ public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException {
+ return new int[0];
+ }
+
+ @Override
+ public int getPackageUid(String packageName, int flags) throws NameNotFoundException {
+ return 0;
+ }
+
+ @Override
+ public int getPackageUidAsUser(String packageName, int userHandle) throws NameNotFoundException {
+ return 0;
+ }
+
+ @Override
+ public int getPackageUidAsUser(String packageName, int flags, int userHandle) throws NameNotFoundException {
return 0;
}
@@ -165,7 +179,7 @@
}
@Override
- public List<PackageInfo> getInstalledPackages(int flags, int userId) {
+ public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
return null;
}
@@ -329,7 +343,7 @@
}
@Override
- public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) {
+ public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) {
return null;
}
@@ -522,7 +536,7 @@
@Override
public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
}
@Override
@@ -544,7 +558,7 @@
@Override
public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
int flags, String installerPackageName, Uri verificationURI,
- ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+ ContainerEncryptionParams encryptionParams) {
}
@Override
@@ -579,12 +593,12 @@
}
@Override
- public int getIntentVerificationStatus(String packageName, int userId) {
+ public int getIntentVerificationStatusAsUser(String packageName, int userId) {
return 0;
}
@Override
- public boolean updateIntentVerificationStatus(String packageName, int status, int userId) {
+ public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) {
return false;
}
@@ -599,12 +613,12 @@
}
@Override
- public String getDefaultBrowserPackageName(int userId) {
+ public String getDefaultBrowserPackageNameAsUser(int userId) {
return null;
}
@Override
- public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+ public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) {
return false;
}
@@ -644,7 +658,7 @@
}
@Override
- public void getPackageSizeInfo(String packageName, int userHandle,
+ public void getPackageSizeInfoAsUser(String packageName, int userHandle,
IPackageStatsObserver observer) {
}
@@ -749,6 +763,11 @@
}
@Override
+ public boolean setPackageSuspendedAsUser(String packageName, boolean suspended, int userId) {
+ return false;
+ }
+
+ @Override
public int getMoveStatus(int moveId) {
return 0;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9c89bfe2..dfbc69b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -19,9 +19,6 @@
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.resources.Density;
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.LinearLayout;
@@ -41,29 +38,18 @@
private static final int WIDTH_DEFAULT = 36;
private static final int WIDTH_SW360 = 40;
private static final int WIDTH_SW600 = 48;
- private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+ protected static final String LAYOUT_XML = "/bars/navigation_bar.xml";
private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
-
- /**
- * Constructor to be used when creating the {@link NavigationBar} as a regular control.
- * This is currently used by the theme editor.
- */
- @SuppressWarnings("unused")
- public NavigationBar(Context context, AttributeSet attrs) {
- this((BridgeContext) context,
- Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
- LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
- ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
- View.LAYOUT_DIRECTION_RTL,
- (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
- 0);
+ public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+ boolean rtlEnabled, int simulatedPlatformVersion) {
+ this(context, density, orientation, isRtl, rtlEnabled, simulatedPlatformVersion,
+ getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML);
}
- public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
- boolean rtlEnabled, int simulatedPlatformVersion) {
- super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
- "navigation_bar.xml", simulatedPlatformVersion);
+ protected NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+ boolean rtlEnabled, int simulatedPlatformVersion, String layoutPath) {
+ super(context, orientation, layoutPath, "navigation_bar.xml", simulatedPlatformVersion);
int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -117,7 +103,7 @@
view.setLayoutParams(layoutParams);
}
- private static int getSidePadding(float sw) {
+ protected int getSidePadding(float sw) {
if (sw >= 400) {
return PADDING_WIDTH_SW400;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
new file mode 100644
index 0000000..0435280
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.layoutlib.bridge.bars;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Navigation Bar for the Theme Editor preview.
+ *
+ * For small bars, it is identical to {@link NavigationBar}.
+ * But wide bars from {@link NavigationBar} are too wide for the Theme Editor preview.
+ * To solve that problem, {@link ThemePreviewNavigationBar} use the layout for small bars,
+ * and have no padding on the sides. That way, they have a similar look as the true ones,
+ * and they fit in the Theme Editor preview.
+ */
+public class ThemePreviewNavigationBar extends NavigationBar {
+ private static final int PADDING_WIDTH_SW600 = 0;
+
+ @SuppressWarnings("unused")
+ public ThemePreviewNavigationBar(Context context, AttributeSet attrs) {
+ super((BridgeContext) context,
+ Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+ LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+ ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+ View.LAYOUT_DIRECTION_RTL,
+ (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
+ 0, LAYOUT_XML);
+ }
+
+ @Override
+ protected int getSidePadding(float sw) {
+ if (sw >= 600) {
+ return PADDING_WIDTH_SW600;
+ }
+ return super.getSidePadding(sw);
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5534cad..76c679c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -170,18 +170,14 @@
public int maxScansToCache;
/**
* if maxPeriodInMs is non zero or different than period, then this bucket is
- * an exponential backoff bucket and the scan period will grow exponentially
- * as per formula: actual_period(N) = period ^ (N/(step_count+1))
- * to a maximum period of max_period.
+ * a truncated binary exponential backoff bucket and the scan period will grow
+ * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
+ * to maxPeriodInMs
*/
public int maxPeriodInMs;
/**
- * for exponential back off bucket: multiplier: new_period=old_period*exponent
- */
- public int exponent;
- /**
- * for exponential back off bucket, number of scans performed at a given
- * period and until the exponent is applied
+ * for truncated binary exponential back off bucket, number of scans to perform
+ * for a given period
*/
public int stepCount;
@@ -198,7 +194,6 @@
dest.writeInt(numBssidsPerScan);
dest.writeInt(maxScansToCache);
dest.writeInt(maxPeriodInMs);
- dest.writeInt(exponent);
dest.writeInt(stepCount);
if (channels != null) {
@@ -226,7 +221,6 @@
settings.numBssidsPerScan = in.readInt();
settings.maxScansToCache = in.readInt();
settings.maxPeriodInMs = in.readInt();
- settings.exponent = in.readInt();
settings.stepCount = in.readInt();
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];